
Hello, I would like to add more asynchronous event sources to asio, like: - input events for mouse, keyboard and joystick .. - window exposure, move, resize events in some generic form, - generic "quit" events - file alteration With directFB/X11/Unix/Linux most of that can be done directly through select or epoll. But since reading the message and parsing events is mostly done by a third party library, I would only need the reactor part for these. Is this possible with asio? According to msdn it seems to be possible to create so called event objects for direct input devices. I am no win32 expert so I do not know if one can combine that with completion ports? Regards Andreas Pokorny

Andreas Pokorny wrote:
Hello,
I would like to add more asynchronous event sources to asio, like: - input events for mouse, keyboard and joystick .. - window exposure, move, resize events in some generic form, - generic "quit" events - file alteration
With directFB/X11/Unix/Linux most of that can be done directly through select or epoll. But since reading the message and parsing events is mostly done by a third party library, I would only need the reactor part for these. Is this possible with asio?
According to msdn it seems to be possible to create so called event objects for direct input devices. I am no win32 expert so I do not know if one can combine that with completion ports?
Asio is not really intended for those use cases as, in general, user interface events follow quite a different model to things like files and sockets. If you want to integrate events from these sources the easiest approach is probably to wait for them externally to asio and then use io_service::post() to execute the handlers (or alternatively write a custom asio service to do the same thing), but since you're not using asio for anything else it doesn't seem worth it to me. You're welcome to reuse any bits of asio that you find useful, though. Cheers, Chris

Christopher Kohlhoff wrote
Andreas Pokorny wrote:
But since reading the message and parsing events is mostly done by a third party library, I would only need the reactor part for these. Is this possible with asio?
According to msdn it seems to be possible to create so called event objects for direct input devices. I am no win32 expert so I do not know if one can combine that with completion ports?
Asio is not really intended for those use cases as, in general, user interface events follow quite a different model to things like files and sockets. If you want to integrate events from these sources the easiest approach is probably to wait for them externally to asio and then use io_service::post() to execute the handlers (or alternatively write a custom asio service to do the same thing), but since you're not using asio for anything else it doesn't seem worth it to me. You're welcome to reuse any bits of asio that you find useful, though.
Oh you got me wrong here, I wanted to use the deadline timers and probably several network connections with low traffic. So I thought if there was a completion criteria that says, "anything to read", I could do pretty much everything I need with the existing asio. Well, at least on Unix-like systems (x11,file alteration, directfb; linux joysticks can be easily parsed into a event data structure). Windows seems like a completely different story. kind regards Andreas Pokorny

Christopher Kohlhoff <chris@kohlhoff.com> writes:
Andreas Pokorny wrote:
Hello,
I would like to add more asynchronous event sources to asio, like: - input events for mouse, keyboard and joystick .. - window exposure, move, resize events in some generic form, - generic "quit" events - file alteration
With directFB/X11/Unix/Linux most of that can be done directly through select or epoll. But since reading the message and parsing events is mostly done by a third party library, I would only need the reactor part for these. Is this possible with asio?
According to msdn it seems to be possible to create so called event objects for direct input devices. I am no win32 expert so I do not know if one can combine that with completion ports?
Asio is not really intended for those use cases as, in general, user interface events follow quite a different model to things like files and sockets. If you want to integrate events from these sources the easiest approach is probably to wait for them externally to asio and then use io_service::post() to execute the handlers (or alternatively write a custom asio service to do the same thing), but since you're not using asio for anything else it doesn't seem worth it to me. You're welcome to reuse any bits of asio that you find useful, though.
This issue is actually very serious and greatly limits the usability of asio, nearly to the point of not being useful at all. A Linux program might want to communicate via some network sockets and pipes, handle inotify notifications (an event structure is read from a file descriptor), and perhaps use Xlib to communicate over a network socket (which means Xlib must do the actual reading/writing, but not necessarily the polling), all using only a single thread. Currently, there is of course no way to do this with asio, and having one thread for asio to do the network socket communication and another thread with some other reactor implementation (like libevent) to do everything else isn't very desirable, and it becomes preferable to just not use asio at all. It seems that one possible solution is to provide an interface for a file descriptor reactor event source only on platforms that use a reactor implementation internally (Unix platforms). -- Jeremy Maitin-Shepard

Hello, 2007/9/11, Christopher Kohlhoff <chris@kohlhoff.com>:
Asio is not really intended for those use cases as, in general, user interface events follow quite a different model to things like files and sockets. [...]
Where is that difference?
From the users point of view it should be quite similar: from the tutorials: io_service io;
deadline_timer t(io, boost::posix_time::seconds(5)); t.async_wait(print); from my phantasy: joystick joy(io, "stickname"); joy.async_axis( boost::bind(handle_axis, joy, placeholders::error )); joy.async_button( boost::bind(handle_button, joy, placeholders::joystick::button_id, placeholders::error )); ... kind regards Andreas Pokorny

On 9/11/07, Christopher Kohlhoff <chris@kohlhoff.com> wrote:
Hi Christopher,
Asio is not really intended for those use cases as, in general, user interface events follow quite a different model to things like files and sockets.
I'm writing a GUI library based on win32gui use syntax. It is still at an very early development phase. But it seem to me it would really benefit from io_service demuxer. And should reduce greatly threading bugs from the user.
If you want to integrate events from these sources the easiest approach is probably to wait for them externally to asio and then use io_service::post() to execute the handlers (or alternatively write a custom asio service to do the same thing),
The parenthesed proposal seem the best to me.
but since you're not using asio for anything else it doesn't seem worth it to me. You're welcome to reuse any bits of asio that you find useful, though.
IMO, using io_service for GUI/input could greatly improve portability, and when using IO it would be a lot easier to make the application responsive by using asynchronous IO. Then the whole application becomes async.
Cheers, Chris
Best regards, -- Felipe Magno de Almeida

On Tue, Sep 11, 2007 at 8:43 AM, Christopher Kohlhoff <chris@kohlhoff.com> wrote:
Andreas Pokorny wrote:
Hello,
I would like to add more asynchronous event sources to asio, like: - input events for mouse, keyboard and joystick .. - window exposure, move, resize events in some generic form, - generic "quit" events
[snip]
Asio is not really intended for those use cases as, in general, user interface events follow quite a different model to things like files and sockets.
I'm writing a GUI library, and I wanted to use the asio concepts in it. For example, I find it very compelling that every window has a member-function that returns a io_service::strand to which one can post messages to the window thread. This would work well with all mainstream toolkits and the win32 API. But how would this work with asio implementation? Can a service be appended to a io_service, and have its own demultiplexer function control the thread running the run member function? The selector_service wouldn't work either I think. Any way this could be accomplished? [snip]
Cheers, Chris
Regards, -- Felipe Magno de Almeida

On Thursday 07 August 2008 04:00:39 Felipe Magno de Almeida wrote:
I'm writing a GUI library, and I wanted to use the asio concepts in it. For example, I find it very compelling that every window has a member-function that returns a io_service::strand to which one can post messages to the window thread. This would work well with all mainstream toolkits and the win32 API. But how would this work with asio implementation? Can a service be appended to a io_service, and have its own demultiplexer function control the thread running the run member function?
You can make your own service that has a thread of its own (like the resolver service does) and from it you can post() events to the io_service event queue so that the thread(s) that perform run() on the io_service will handle them. This is a pretty generic way one can handle any asynchronous sources to asio (by using additional threads). -- Mihai RUSU Email: dizzy@roedu.net "Linux is obsolete" -- AST

On Thu, Aug 7, 2008 at 5:33 AM, dizzy <dizzy@roedu.net> wrote:
On Thursday 07 August 2008 04:00:39 Felipe Magno de Almeida wrote:
I'm writing a GUI library, and I wanted to use the asio concepts in it. For example, I find it very compelling that every window has a member-function that returns a io_service::strand to which one can post messages to the window thread. This would work well with all mainstream toolkits and the win32 API. But how would this work with asio implementation? Can a service be appended to a io_service, and have its own demultiplexer function control the thread running the run member function?
You can make your own service that has a thread of its own (like the resolver service does) and from it you can post() events to the io_service event queue so that the thread(s) that perform run() on the io_service will handle them.
This is a pretty generic way one can handle any asynchronous sources to asio (by using additional threads).
That won't work. I have to wait for events on the thread that run is running in, which is the user thread and is the same that creates the windows.
-- Mihai RUSU Email: dizzy@roedu.net
Regards, -- Felipe Magno de Almeida

On Thursday 07 August 2008 11:52:37 Felipe Magno de Almeida wrote:
On Thu, Aug 7, 2008 at 5:33 AM, dizzy <dizzy@roedu.net> wrote:
On Thursday 07 August 2008 04:00:39 Felipe Magno de Almeida wrote:
I'm writing a GUI library, and I wanted to use the asio concepts in it. For example, I find it very compelling that every window has a member-function that returns a io_service::strand to which one can post messages to the window thread. This would work well with all mainstream toolkits and the win32 API. But how would this work with asio implementation? Can a service be appended to a io_service, and have its own demultiplexer function control the thread running the run member function?
You can make your own service that has a thread of its own (like the resolver service does) and from it you can post() events to the io_service event queue so that the thread(s) that perform run() on the io_service will handle them.
This is a pretty generic way one can handle any asynchronous sources to asio (by using additional threads).
That won't work. I have to wait for events on the thread that run is running in, which is the user thread and is the same that creates the windows.
Is this a limitation of the GUI framework? You only need to _wait_ for the events in this internal thread, the actual dispatching still happens through normal asio mechanisms to the threads that execute run(). If your GUI somehow assigns some kind of ownership of the window creator thread so only that thread can wait/query for events then this is a serious limitation because it won't allow you to easily in the future have multiple threads execute run() for scalability reasons. You won't be able to _really_ wait events in the same thread since that already blocks using some OS dependent I/O notification mechanism (say it blocks in select()) which may not permit notification of GUI events anyways (not to mention this does not seem to be a configurable part of asio without depending on "detail" stuff). A workaround is to get all events be some sort of I/O events (ex using socketpair) but then you need the GUI to use the socketpair or you need that separate thread to wait for GUI events and post to the socketpair (but then the socketpair is not needed since you can directly post() events on the io_service). Another general solution but that has its own shortcomings is to have your own event loop that calls run_one() and on each iteration you "peek" into the other event source (the GUI event source you want to integrate with asio). This works fine if asio is busy but if not you can also program a timer with asio so it will make run_one() return at least once per the time configured in the timer. It obviously has the problem that if asio is not busy GUI events will be handled at this timer granularity. If GUI events are more important than asio generated ones then you could do the reverse (make an event loop that calls some sort of run_one() function for the GUI events, a function that waits for at least an event and dispatches it and returns and then you use io_service.peek() to execute possible asio queued events). -- Mihai RUSU Email: dizzy@roedu.net "Linux is obsolete" -- AST

On Thu, Aug 7, 2008 at 7:57 AM, dizzy <dizzy@roedu.net> wrote:
On Thursday 07 August 2008 11:52:37 Felipe Magno de Almeida wrote:
On Thu, Aug 7, 2008 at 5:33 AM, dizzy <dizzy@roedu.net> wrote:
On Thursday 07 August 2008 04:00:39 Felipe Magno de Almeida wrote:
[snip]
That won't work. I have to wait for events on the thread that run is running in, which is the user thread and is the same that creates the windows.
Is this a limitation of the GUI framework?
It is a limitation of the low-level graphical interfaces, like win32 for example. If I execute GetMessage, it will only return events of windows which were created on that thread.
You only need to _wait_ for the events in this internal thread,
Yes, that's my limitation. I don't want to create the windows in another thread, since that might confuse users that need to extend functionality using raw handles.
the actual dispatching still happens through normal asio mechanisms to the threads that execute run(). If your GUI somehow assigns some kind of ownership of the window creator thread so only that thread can wait/query for events then this is a serious limitation because it won't allow you to easily in the future have multiple threads execute run() for scalability reasons.
Unfortunately that's not my limitation, but that of the toolkits. GTK+, Qt and win32 have it. In a matter of fact, I don't know one that doesn't.
You won't be able to _really_ wait events in the same thread since that already blocks using some OS dependent I/O notification mechanism (say it blocks in select()) which may not permit notification of GUI events anyways (not to mention this does not seem to be a configurable part of asio without depending on "detail" stuff). A workaround is to get all events be some sort of I/O events (ex using socketpair) but then you need the GUI to use the socketpair or you need that separate thread to wait for GUI events and post to the socketpair (but then the socketpair is not needed since you can directly post() events on the io_service).
Another general solution but that has its own shortcomings is to have your own event loop that calls run_one() and on each iteration you "peek" into the other event source (the GUI event source you want to integrate with asio). This works fine if asio is busy but if not you can also program a timer with asio so it will make run_one() return at least once per the time configured in the timer. It obviously has the problem that if asio is not busy GUI events will be handled at this timer granularity. If GUI events are more important than asio generated ones then you could do the reverse (make an event loop that calls some sort of run_one() function for the GUI events, a function that waits for at least an event and dispatches it and returns and then you use io_service.peek() to execute possible asio queued events).
That's probably not enough. Maybe some design thinking on asio part should be done? I obviously don't want to impose this, but just think how cool it would be that a single-threaded (at least for most platforms) GUI client could be created, without blocking the user interface with operations that could take quite some time to execute? No synchronizations for example. It might even be easier to write gui clients with asynchronous IO than with synchronous.
-- Mihai RUSU Email: dizzy@roedu.net "Linux is obsolete" -- AST
Regards, -- Felipe Magno de Almeida

On Thursday 07 August 2008 14:26:23 Felipe Magno de Almeida wrote:
That's probably not enough. Maybe some design thinking on asio part should be done?
It's not (just) about asio design.
I obviously don't want to impose this, but just think how cool it would be that a single-threaded (at least for most platforms) GUI client could be created, without blocking the user interface with operations that could take quite some time to execute? No synchronizations for example. It might even be easier to write gui clients with asynchronous IO than with synchronous.
Of course it's cool but there are limitations given by the OS and the GUI framework you use that do not allow that to happen. Do you have on all asio supported platforms an OS system call that can wait for events either from sockets or GUI? If so then you can do it (with some modification on asio to allow extensibility at that level). If not then you can't do it no matter how you design asio. -- Mihai RUSU Email: dizzy@roedu.net "Linux is obsolete" -- AST

. On Thu, Aug 7, 2008 at 9:05 AM, dizzy <dizzy@roedu.net> wrote:
On Thursday 07 August 2008 14:26:23 Felipe Magno de Almeida wrote:
[snip]
Of course it's cool but there are limitations given by the OS and the GUI framework you use that do not allow that to happen. Do you have on all asio supported platforms an OS system call that can wait for events either from sockets or GUI? If so then you can do it (with some modification on asio to allow extensibility at that level). If not then you can't do it no matter how you design asio.
I don't know about linux, but win32 can wait for IO completion ports on any thread, so while GUI has this limitation, AIOs wouldn't, so they could live happily ever after. ;). Am I missing anything?
-- Mihai RUSU Email: dizzy@roedu.net "Linux is obsolete" -- AST
Regards, -- Felipe Magno de Almeida

On Thursday 07 August 2008 15:44:03 Felipe Magno de Almeida wrote:
.
On Thu, Aug 7, 2008 at 9:05 AM, dizzy <dizzy@roedu.net> wrote:
On Thursday 07 August 2008 14:26:23 Felipe Magno de Almeida wrote:
[snip]
Of course it's cool but there are limitations given by the OS and the GUI framework you use that do not allow that to happen. Do you have on all asio supported platforms an OS system call that can wait for events either from sockets or GUI? If so then you can do it (with some modification on asio to allow extensibility at that level). If not then you can't do it no matter how you design asio.
I don't know about linux, but win32 can wait for IO completion ports on any thread, so while GUI has this limitation, AIOs wouldn't, so they could live happily ever after. ;). Am I missing anything?
OK I think I get it (finally). Although there still may be other solutions with whatever Win32 specific API (which I do not know since I'm more a POSIX programmer) you want the later solution I proposed but to be able to be done from within asio somehow. So you want io_service.run() to block in GUI event receiving but have an internal thread that blocks with whatever reactor/completion ports method for the events that asio usually handles (right now at least). Interesting. Looking into io_service implementation it does not appear that generalizing io_service is very hard since it does seem to relay the functionality to a "service" type anyway (that is chosen depending on the platform). So what could be done is: - define an IOService concept that should cover what io_service::impl_type does right now - have a basic_io_service<typename IOService> template relaying to IOService (this is what io_service already does) - update users that received io_service& to work with typename IOService& (this may be hard I haven't looked into it) - typedef <whatever system I/O provider> SystemIOService; this is the platform based decision that asio makes right now into io_service definition - typedef basic_io_service<SystemIOService> io_service; This allows one to still use io_service as usual but if one wants to change the main event service provider he can write his own IOService type and instantiate basic_io_service on that (and this type can as you said create an internal thread that uses SystemIOService to wait and post asio normal events but in his own main code wait for GUI events). Since it's waiting for the GUI events in the thread that calls run() this should be (under certain situations) the same thread as the one that created the GUI windows. If at least the modification that "io_service&" is taken as a template parameter is made then a faster solution than all those asio modifications is to make your own "io_service" type with similar API as asio's and require all async operations to go through your own io_service which will spawn an internal thread that uses an asio::io_service and blocks into its run() and will wrap every completion handler the user provided so that instead of actually calling the handler it post()s it on your own io_service event queue. So then when you block into your own io_service.run() you will handle either GUI events (which you wait for) or socket events which asio::io_service will catch and dispatch by posting them to your io_service. Hope I'm not missing too much here :) -- Mihai RUSU Email: dizzy@roedu.net "Linux is obsolete" -- AST

On Thu, Aug 7, 2008 at 10:34 AM, dizzy <dizzy@roedu.net> wrote:
On Thursday 07 August 2008 15:44:03 Felipe Magno de Almeida wrote:
.
[snip]
I don't know about linux, but win32 can wait for IO completion ports on any thread, so while GUI has this limitation, AIOs wouldn't, so they could live happily ever after. ;). Am I missing anything?
OK I think I get it (finally). Although there still may be other solutions with whatever Win32 specific API (which I do not know since I'm more a POSIX programmer) you want the later solution I proposed but to be able to be done from within asio somehow. So you want io_service.run() to block in GUI event receiving but have an internal thread that blocks with whatever reactor/completion ports method for the events that asio usually handles (right now at least).
Exactly!
Interesting. Looking into io_service implementation it does not appear that generalizing io_service is very hard since it does seem to relay the functionality to a "service" type anyway (that is chosen depending on the platform). So what could be done is: - define an IOService concept that should cover what io_service::impl_type does right now
That seems necessary.
- have a basic_io_service<typename IOService> template relaying to IOService (this is what io_service already does)
My asio version (boost trunk) doesn't do this. It isn't templated at all. The impl_type typedef is changed at preprocessing time with the implementation type of the platform.
- update users that received io_service& to work with typename IOService& (this may be hard I haven't looked into it)
Well, io_service is better to work with because it can be used as a collection of io services, we need only one to deal with all IOs. If I use IOService instead, I'll be restricting to GUI events. [snip - suggestion based on templated basic_io_service] I think I should create a GUI-aware IOService. Though this works, it would probably have to be enabled explicitly through some kind of preprocessor symbol. It would be nicer if io_service could handle this automatically somehow. A io_service that *only* does name resolving for example could execute some of its thread pools in the thread that execute io_service::run for example. Reducing context-switches. [snip]
-- Mihai RUSU Email: dizzy@roedu.net "Linux is obsolete" -- AST
Thanks, -- Felipe Magno de Almeida

I had a similar problem to this recently when writing a program that used asio and GTK (under Linux), and I thought I'd share my solution here in case it's helpful (it's one you didn't suggest). dizzy wrote:
On Thursday 07 August 2008 11:52:37 Felipe Magno de Almeida wrote: <snip>
That won't work. I have to wait for events on the thread that run is running in, which is the user thread and is the same that creates the windows.
Is this a limitation of the GUI framework? You only need to _wait_ for the events in this internal thread, the actual dispatching still happens through normal asio mechanisms to the threads that execute run(). If your GUI somehow assigns some kind of ownership of the window creator thread so only that thread can wait/query for events then this is a serious limitation because it won't allow you to easily in the future have multiple threads execute run() for scalability reasons.
The problem I was having was that I have one thread running Gtk::Main::run, which does all the GUI event handling, and another thread doing io_service::run(). This broke when anything in the latter thread tried to change the GUI (e.g. to display a message to the user) it couldn't alter the GUI (doing so would cause crashes somewhat at random, presumably because the data structures in question were not locking). Possibly some sort of locking is possible, but a more obvious solution is to require all GUI updates to be done on the GUI thread.
You won't be able to _really_ wait events in the same thread since that already blocks using some OS dependent I/O notification mechanism (say it blocks in select()) which may not permit notification of GUI events anyways (not to mention this does not seem to be a configurable part of asio without depending on "detail" stuff). A workaround is to get all events be some sort of I/O events (ex using socketpair) but then you need the GUI to use the socketpair or you need that separate thread to wait for GUI events and post to the socketpair (but then the socketpair is not needed since you can directly post() events on the io_service).
I don't see a way of coercing the GUI events to be of this form, at least not in a way useful for asio.
Another general solution but that has its own shortcomings is to have your own event loop that calls run_one() and on each iteration you "peek" into the other event source (the GUI event source you want to integrate with asio).
This was roughly my first solution. As you say...
This works fine if asio is busy but if not you can also program a timer with asio so it will make run_one() return at least once per the time configured in the timer. It obviously has the problem that if asio is not busy GUI events will be handled at this timer granularity.
I tried the more naive thing of polling both asio and the GUI with sleeps interspersed, but I couldn't find a sleep that was sufficiently brief (e.g. usleep(0) sleeps for ~10ms, which is too long to get a responsive GUI); would your solution allow a sufficiently fine granularity?
If GUI events are more important than asio generated ones then you could do the reverse (make an event loop that calls some sort of run_one() function for the GUI events, a function that waits for at least an event and dispatches it and returns and then you use io_service.peek() to execute possible asio queued events).
That should work. It would require a way to ensure that suitably marked posts are executed only on the GUI thread; presumably that's possible with something in asio (strands?). My solution is roughly the reverse of your first suggestion: coerce all events to be GUI events and use GTK's run() function only on the GUI thread. This is the 'official' GTK solution, and uses the Glib::Dispatcher class (which I found only after much searching). Glib::Dispatcher works much like boost::signal<void ()>, but the function is called asynchronously on the GUI thread. I used Glib::Dispatcher to build a more general version of itself (called CrossThreadSignal) that takes arguments. I've included the source below for completeness (requires C++0x). I use this for example as a way of posting messages to the GUI with something like // In GUI thread CrossThreadSignal<std::string> messageSignal; messageSignal.connect(sigc::ptr_fun(&writeMessage)); // Then in another thread messageSignal("message"); I suspect the implementation can be improved; in particular it feels like it should be possible to use a lock-free data structure of some kind where I'm using a std::list and a mutex. John // Signal which when called on one thread will be raised // asynchronously on the GUI thread (and thus can safely mess with // widgets) template<typename... Args> class CrossThreadSignal { public: CrossThreadSignal() { callAlert_.connect( sigc::mem_fun(this, &CrossThreadSignal::flush) ); } template<typename Function> void connect(const Function& f) { signal_.connect(f); } void operator()(const Args&... args) { { boost::lock_guard<boost::mutex> lock(pendingCallsMutex_); pendingCalls_.push_back( boost::bind(&CrossThreadSignal::raise, this, args...) ); } callAlert_(); } private: void raise(const Args&... args) { signal_(args...); } typedef decltype( boost::bind( &CrossThreadSignal::raise, ((CrossThreadSignal*)0), *((Args*) 0)... ) ) PendingCall; // Each list entry is a set of arguments std::list<PendingCall> pendingCalls_; boost::mutex pendingCallsMutex_; // Mutex for above list // The trigger that can signal between threads Glib::Dispatcher callAlert_; // Signal to connect to; raised on GUI thread boost::signal<void (const Args&...)> signal_; void flush() { boost::lock_guard<boost::mutex> lock(pendingCallsMutex_); while (!pendingCalls_.empty()) { pendingCalls_.front()(); pendingCalls_.pop_front(); } } };

On Thu, 07 Aug 2008 03:00:39 +0200, Felipe Magno de Almeida <felipe.m.almeida@gmail.com> wrote:
[...]Can a service be appended to a io_service, and have its own demultiplexer function control the thread running the run member function? The selector_service wouldn't work either I think. Any way this could be accomplished?
I've created a simple file monitor for Boost.Asio which notifies an application when a file is changed. You can download the source from http://www.highscore.de/boost/file_monitor.zip. It's not complete but as it is not much code it should give you an idea how to handle new events. Boris
participants (7)
-
Andreas Pokorny
-
Boris
-
Christopher Kohlhoff
-
dizzy
-
Felipe Magno de Almeida
-
Jeremy Maitin-Shepard
-
John Bytheway