NSM: Update documentation.
This commit is contained in:
parent
c1a7848670
commit
1c1817fc41
|
@ -12,8 +12,8 @@
|
||||||
<address>
|
<address>
|
||||||
Jonathan Moore Liles <a href="mailto:male@tuxfamily.org"><male@tuxfamily.org></a><br>
|
Jonathan Moore Liles <a href="mailto:male@tuxfamily.org"><male@tuxfamily.org></a><br>
|
||||||
August 1, 2010<br>
|
August 1, 2010<br>
|
||||||
Version 0.8
|
Version 0.9
|
||||||
</address><hr></div>
|
</address><img src="icon.png" alt="logo"><hr></div>
|
||||||
<div id=body>
|
<div id=body>
|
||||||
<div id=toc>
|
<div id=toc>
|
||||||
<h1 id=toc>Table Of Contents</h1>
|
<h1 id=toc>Table Of Contents</h1>
|
||||||
|
@ -98,7 +98,7 @@ Most graphical applications make available to the user a common set of file oper
|
||||||
These are: New, Open, Save, Save As, Close and Quit or Exit.
|
These are: New, Open, Save, Save As, Close and Quit or Exit.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The following sub-sections describe how these options should behave when the application is part of an NSM session. These rules only apply when session management is active (that is, after the <tt>announce</tt> handshake described in the <a class=int href="#"></a> section). In order to provide a consistent and predictable user experience, it is critically important for applications to adhere to these guidelines.
|
The following sub-sections describe how these options should behave when the application is part of an NSM session. These rules only apply when session management is active (that is, after the <tt>announce</tt> handshake described in the <a class=int href="#n:1.2.">1.2. NSM OSC Protocol</a> section). In order to provide a consistent and predictable user experience, it is critically important for applications to adhere to these guidelines.
|
||||||
</p>
|
</p>
|
||||||
<h3 id="n:1.1.1.">1.1.1. New</h3>
|
<h3 id="n:1.1.1.">1.1.1. New</h3>
|
||||||
<p>
|
<p>
|
||||||
|
@ -131,7 +131,7 @@ The application may, however, elect to implement an option called 'Export from S
|
||||||
</p>
|
</p>
|
||||||
<h3 id="n:1.1.6.">1.1.6. Quit or Exit</h3>
|
<h3 id="n:1.1.6.">1.1.6. Quit or Exit</h3>
|
||||||
<p>
|
<p>
|
||||||
This option may behave as normal (even possibly asking the user to confirm exiting).
|
This option may behave as normal (possibly asking the user to confirm exiting).
|
||||||
</p>
|
</p>
|
||||||
<h2 id="n:1.2.">1.2. NSM OSC Protocol</h2>
|
<h2 id="n:1.2.">1.2. NSM OSC Protocol</h2>
|
||||||
<p>
|
<p>
|
||||||
|
@ -156,10 +156,10 @@ If <tt>NSM_URL</tt> is undefined, invalid, or unreachable, then the client shoul
|
||||||
<tt>api_version_major</tt> and <tt>api_version_minor</tt> must be the two parts of the version number of the NSM API as defined by this document.
|
<tt>api_version_major</tt> and <tt>api_version_minor</tt> must be the two parts of the version number of the NSM API as defined by this document.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Note that if the application intends to register JACK clients, <tt>application_name</tt> <b>MUST</b> be the same as the name that would normally by passed to <tt>jack_client_open</tt>. For example, Non-Mixer sends "Non-Mixer" as its <tt>application_name</tt>. Applications <b>MUST NOT</b> register their JACK clients until receiving an <tt>open</tt> message; the <tt>open</tt> message will provide a unique client name prefix suitable for passing to JACK. This is probably the most complex requirement of the NSM API, but it isn't difficult to implement, especially if the application simply wishes to delay its initialization process breifly while awaiting the <tt>announce</tt> reply and subsequent <tt>open</tt> message.
|
Note that if the application intends to register JACK clients, <tt>application_name</tt> <b>MUST</b> be the same as the name that would normally be passed to <tt>jack_client_open</tt>. For example, Non-Mixer sends "Non-Mixer" as its <tt>application_name</tt>. Applications <b>MUST NOT</b> register their JACK clients until receiving an <tt>open</tt> message; the <tt>open</tt> message will provide a unique client name prefix suitable for passing to JACK. This is probably the most complex requirement of the NSM API, but it isn't difficult to implement, especially if the application simply wishes to delay its initialization process breifly while awaiting the <tt>announce</tt> reply and subsequent <tt>open</tt> message.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<tt>capabilities</tt> <b>MUST</b> be a string containing a colon separated list of the special capabilities the client possesses. e.g. ":dirty:switch:progress:"
|
<tt>capabilities</tt> <b>MUST</b> be a string containing a colon separated list of the special capabilities the client possesses. e.g. <tt>:dirty:switch:progress:</tt>
|
||||||
</p>
|
</p>
|
||||||
<center><div class="fig table"><table id="Fig.1.1" border=1>
|
<center><div class="fig table"><table id="Fig.1.1" border=1>
|
||||||
<caption>
|
<caption>
|
||||||
|
@ -226,7 +226,7 @@ The following table defines possible values of <tt>error_code</tt>:
|
||||||
Compliant clients <b>MUST</b> accept the client control messages described in this section. All client control messages <b>REQUIRE</b> a response. Responses <b>MUST</b> be delivered back to the sender (NSM) from the same socket used by the client in its <tt>announce</tt> message (by using <tt>lo_send_from</tt>) <b>AFTER</b> the action has been completed or if an error is encountered. The required response is described in the subsection for each message.
|
Compliant clients <b>MUST</b> accept the client control messages described in this section. All client control messages <b>REQUIRE</b> a response. Responses <b>MUST</b> be delivered back to the sender (NSM) from the same socket used by the client in its <tt>announce</tt> message (by using <tt>lo_send_from</tt>) <b>AFTER</b> the action has been completed or if an error is encountered. The required response is described in the subsection for each message.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If there is an error and the action cannot be completed, then <tt>error_code</tt> <b>MUST</b> be set to a valid error code (see <a href="#Fig."></a>) and <tt>message</tt> to a string describing the problem (suitable for display to the user).
|
If there is an error and the action cannot be completed, then <tt>error_code</tt> <b>MUST</b> be set to a valid error code (see <a class=int href="#n:1.2.5.">1.2.5. Error Code Definitions</a>) and <tt>message</tt> to a string describing the problem (suitable for display to the user).
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The reply can take one of the following two forms, where <tt>path</tt> <b>MUST</b> be the path of the message being replied to (e.g. "<i>nsm/client/save"</i>:
|
The reply can take one of the following two forms, where <tt>path</tt> <b>MUST</b> be the path of the message being replied to (e.g. "<i>nsm/client/save"</i>:
|
||||||
|
@ -316,8 +316,9 @@ Or
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
</table></div>
|
</table></div>
|
||||||
<p>
|
<p>
|
||||||
The client <b>MUST</b> immediately save the current application specific project data to the project path previously established in the 'open' message. <b>UNDER NO CIRCUMSTANCES</b> should a dialog be displayed to the user (giving a choice of where to save, etc.) This message will only be delivered after a previous <tt>open</tt> message, and may be sent any number of times within the course of a session (including zero, if the user aborts the session).
|
This message will only be delivered after a previous <tt>open</tt> message, and may be sent any number of times within the course of a session (including zero, if the user aborts the session).
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
<h5 id="n:1.2.2.3.1.">1.2.2.3.1. Response</h5>
|
<h5 id="n:1.2.2.3.1.">1.2.2.3.1. Response</h5>
|
||||||
<p>
|
<p>
|
||||||
The client <b>MUST</b> respond to the 'save' message with:
|
The client <b>MUST</b> respond to the 'save' message with:
|
||||||
|
@ -427,7 +428,7 @@ If the server publishes the <tt>:server_control:</tt> capability, then clients c
|
||||||
The session manager not only manages clients via OSC, but it is itself controlled via OSC messages. The server responds to the following messages.
|
The session manager not only manages clients via OSC, but it is itself controlled via OSC messages. The server responds to the following messages.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
All of the following messages will be responded to back to the sender's address with one of the two following messages:
|
All of the following messages will be responded to, at the sender's address, with one of the two following messages:
|
||||||
</p>
|
</p>
|
||||||
<div class="fig example"><table width=100%><tr><td><pre>
|
<div class="fig example"><table width=100%><tr><td><pre>
|
||||||
/reply s:path s:message
|
/reply s:path s:message
|
||||||
|
@ -456,57 +457,59 @@ The possible errors are:
|
||||||
</table></div></center>
|
</table></div></center>
|
||||||
<dl>
|
<dl>
|
||||||
<dt><em>/nsm/server/add s:path_to_executable</em></dt>
|
<dt><em>/nsm/server/add s:path_to_executable</em></dt>
|
||||||
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
Adds a client to the current session.
|
Adds a client to the current session.
|
||||||
</p>
|
</p>
|
||||||
</dl><dl>
|
<dl>
|
||||||
<dt><em>/nsm/server/save</em></dt>
|
<dt><em>/nsm/server/save</em></dt>
|
||||||
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
Saves the current session.
|
Saves the current session.
|
||||||
</p>
|
</p>
|
||||||
</dl><dl>
|
<dl>
|
||||||
<dt><em>/nsm/server/load s:project_name</em></dt>
|
<dt><em>/nsm/server/load s:project_name</em></dt>
|
||||||
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
Saves the current session and loads a new session.
|
Saves the current session and loads a new session.
|
||||||
</p>
|
</p>
|
||||||
</dl><dl>
|
<dl>
|
||||||
<dt><em>/nsm/server/new s:project_name</em></dt>
|
<dt><em>/nsm/server/new s:project_name</em></dt>
|
||||||
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
Saves the current session and creates a new session.
|
Saves the current session and creates a new session.
|
||||||
</p>
|
</p>
|
||||||
</dl><dl>
|
<dl>
|
||||||
|
<dt><em>/nsm/server/duplicate s:new_project</em></dt>
|
||||||
|
</dl>
|
||||||
|
<p>
|
||||||
|
Saves and closes the current session, makes a copy, and opens it.
|
||||||
|
</p>
|
||||||
|
<dl>
|
||||||
<dt><em>/nsm/server/close</em></dt>
|
<dt><em>/nsm/server/close</em></dt>
|
||||||
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
Saves and closes the current session.
|
Saves and closes the current session.
|
||||||
</p>
|
</p>
|
||||||
</dl><dl>
|
<dl>
|
||||||
<dt><em>/nsm/server/abort</em></dt>
|
<dt><em>/nsm/server/abort</em></dt>
|
||||||
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
Closes the current session <b>WITHOUT SAVING</b>
|
Closes the current session <b>WITHOUT SAVING</b>
|
||||||
</p>
|
</p>
|
||||||
</dl><dl>
|
<dl>
|
||||||
<dt><em>/nsm/server/quit</em></dt>
|
<dt><em>/nsm/server/quit</em></dt>
|
||||||
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
Saves and closes the current session and terminates the server.
|
Saves and closes the current session and terminates the server.
|
||||||
</p>
|
</p>
|
||||||
</dl><dl>
|
|
||||||
<dt><em>/nsm/server/duplicate s:new_project </em></dt>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt><em>/nsm/server/list </em></dt>
|
<dt><em>/nsm/server/list </em></dt>
|
||||||
|
</dl>
|
||||||
<p>
|
<p>
|
||||||
Lists available projects. One <tt>/reply</tt> message will be sent for each existing project.
|
Lists available projects. One <tt>/reply</tt> message will be sent for each existing project.
|
||||||
</p>
|
</p>
|
||||||
</dl><h4 id="n:1.2.7.1.">1.2.7.1. Client to Client Communication</h4>
|
<h4 id="n:1.2.7.1.">1.2.7.1. Client to Client Communication</h4>
|
||||||
<p>
|
<p>
|
||||||
If the server includes <tt>:broadcast:</tt> in its capability string, then clients may send broadcast messages to each other through the NSM server. Clients may send messages to the server at the path <tt>/nsm/server/broadcast</tt>.
|
If the server includes <tt>:broadcast:</tt> in its capability string, then clients may send broadcast messages to each other through the NSM server. Clients may send messages to the server at the path <tt>/nsm/server/broadcast</tt>.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
! title Non Session Management API
|
! title Non Session Management API
|
||||||
! author Jonathan Moore Liles #(email,male@tuxfamily.org)
|
! author Jonathan Moore Liles #(email,male@tuxfamily.org)
|
||||||
! date August 1, 2010
|
! date August 1, 2010
|
||||||
! revision Version 0.8
|
! revision Version 0.9
|
||||||
|
! extra #(image,logo,icon.png)
|
||||||
|
|
||||||
-- Table Of Contents
|
-- Table Of Contents
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@
|
||||||
The following sub-sections describe how these options should behave when
|
The following sub-sections describe how these options should behave when
|
||||||
the application is part of an NSM session. These rules only apply
|
the application is part of an NSM session. These rules only apply
|
||||||
when session management is active (that is, after the `announce`
|
when session management is active (that is, after the `announce`
|
||||||
handshake described in the #(ref,NSM OSC Protocol) section).
|
handshake described in the #(ref,Non Session Management API::NSM OSC Protocol) section).
|
||||||
|
|
||||||
In order to provide a consistent and predictable user experience, it
|
In order to provide a consistent and predictable user experience, it
|
||||||
is critically important for applications to adhere to these
|
is critically important for applications to adhere to these
|
||||||
|
@ -100,7 +101,7 @@
|
||||||
|
|
||||||
::: Quit or Exit
|
::: Quit or Exit
|
||||||
|
|
||||||
This option may behave as normal (even possibly asking the user to
|
This option may behave as normal (possibly asking the user to
|
||||||
confirm exiting).
|
confirm exiting).
|
||||||
|
|
||||||
:: NSM OSC Protocol
|
:: NSM OSC Protocol
|
||||||
|
@ -135,7 +136,7 @@
|
||||||
|
|
||||||
Note that if the application intends to register JACK clients,
|
Note that if the application intends to register JACK clients,
|
||||||
`application\_name` *MUST* be the same as the name that would
|
`application\_name` *MUST* be the same as the name that would
|
||||||
normally by passed to `jack\_client\_open`. For example, Non-Mixer
|
normally be passed to `jack\_client\_open`. For example, Non-Mixer
|
||||||
sends "Non-Mixer" as its `application\_name`. Applications *MUST
|
sends "Non-Mixer" as its `application\_name`. Applications *MUST
|
||||||
NOT* register their JACK clients until receiving an `open` message;
|
NOT* register their JACK clients until receiving an `open` message;
|
||||||
the `open` message will provide a unique client name prefix suitable
|
the `open` message will provide a unique client name prefix suitable
|
||||||
|
@ -147,7 +148,7 @@
|
||||||
|
|
||||||
`capabilities` *MUST* be a string containing a colon separated list
|
`capabilities` *MUST* be a string containing a colon separated list
|
||||||
of the special capabilities the client
|
of the special capabilities the client
|
||||||
possesses. e.g. ":dirty:switch:progress:"
|
possesses. e.g. `:dirty:switch:progress:`
|
||||||
|
|
||||||
// Available Client Capabilities
|
// Available Client Capabilities
|
||||||
[[ Name, Description
|
[[ Name, Description
|
||||||
|
@ -207,7 +208,7 @@
|
||||||
the subsection for each message.
|
the subsection for each message.
|
||||||
|
|
||||||
If there is an error and the action cannot be completed, then
|
If there is an error and the action cannot be completed, then
|
||||||
`error\_code` *MUST* be set to a valid error code (see #(fig,Error Code Definitions))
|
`error\_code` *MUST* be set to a valid error code (see #(ref,Non Session Management API::NSM OSC Protocol::Error Code Definitions))
|
||||||
and `message` to a string describing the problem (suitable
|
and `message` to a string describing the problem (suitable
|
||||||
for display to the user).
|
for display to the user).
|
||||||
|
|
||||||
|
@ -318,15 +319,24 @@
|
||||||
|
|
||||||
> /nsm/client/save
|
> /nsm/client/save
|
||||||
|
|
||||||
The client *MUST* immediately save the current application specific
|
|
||||||
project data to the project path previously established in the
|
|
||||||
'open' message. *UNDER NO CIRCUMSTANCES* should a dialog be
|
|
||||||
displayed to the user (giving a choice of where to save, etc.)
|
|
||||||
|
|
||||||
This message will only be delivered after a previous `open` message,
|
This message will only be delivered after a previous `open` message,
|
||||||
and may be sent any number of times within the course of a session
|
and may be sent any number of times within the course of a session
|
||||||
(including zero, if the user aborts the session).
|
(including zero, if the user aborts the session).
|
||||||
|
|
||||||
|
If able to, the client *MUST* immediately save the current
|
||||||
|
application specific project data to the project path previously
|
||||||
|
established in the 'open' message. *UNDER NO CIRCUMSTANCES* should a
|
||||||
|
dialog be displayed to the user (giving a choice of where to save,
|
||||||
|
etc.)
|
||||||
|
|
||||||
|
However, if the client is incapable of saving at the specific moment
|
||||||
|
without disturbing the user (e.g. a JACK client that can't save
|
||||||
|
while the transport is rolling without causing massive XRUNS), then
|
||||||
|
the client may respond to "/error" with ERR_NOT_NOW and a string
|
||||||
|
explaining exactly why the save could not be completed (so that, in
|
||||||
|
this example, the user knows that they have to stop the transport in
|
||||||
|
order to save).
|
||||||
|
|
||||||
::::: Response
|
::::: Response
|
||||||
|
|
||||||
The client *MUST* respond to the 'save' message with:
|
The client *MUST* respond to the 'save' message with:
|
||||||
|
@ -438,8 +448,8 @@
|
||||||
itself controlled via OSC messages. The server responds to the
|
itself controlled via OSC messages. The server responds to the
|
||||||
following messages.
|
following messages.
|
||||||
|
|
||||||
All of the following messages will be responded to back to the
|
All of the following messages will be responded to, at the sender's
|
||||||
sender's address with one of the two following messages:
|
address, with one of the two following messages:
|
||||||
|
|
||||||
> /reply s:path s:message
|
> /reply s:path s:message
|
||||||
|
|
||||||
|
@ -461,33 +471,39 @@
|
||||||
[[ ERR_UNSAVED_CHANGES, Unsaved changes would be lost
|
[[ ERR_UNSAVED_CHANGES, Unsaved changes would be lost
|
||||||
|
|
||||||
= /nsm/server/add s:path_to_executable
|
= /nsm/server/add s:path_to_executable
|
||||||
|
|
||||||
Adds a client to the current session.
|
Adds a client to the current session.
|
||||||
|
|
||||||
= /nsm/server/save
|
= /nsm/server/save
|
||||||
|
|
||||||
Saves the current session.
|
Saves the current session.
|
||||||
|
|
||||||
= /nsm/server/load s:project_name
|
= /nsm/server/load s:project_name
|
||||||
|
|
||||||
Saves the current session and loads a new session.
|
Saves the current session and loads a new session.
|
||||||
|
|
||||||
= /nsm/server/new s:project_name
|
= /nsm/server/new s:project_name
|
||||||
|
|
||||||
Saves the current session and creates a new session.
|
Saves the current session and creates a new session.
|
||||||
|
|
||||||
|
= /nsm/server/duplicate s:new_project
|
||||||
|
|
||||||
|
Saves and closes the current session, makes a copy, and opens it.
|
||||||
|
|
||||||
= /nsm/server/close
|
= /nsm/server/close
|
||||||
|
|
||||||
Saves and closes the current session.
|
Saves and closes the current session.
|
||||||
|
|
||||||
= /nsm/server/abort
|
= /nsm/server/abort
|
||||||
|
|
||||||
Closes the current session *WITHOUT SAVING*
|
Closes the current session *WITHOUT SAVING*
|
||||||
|
|
||||||
= /nsm/server/quit
|
= /nsm/server/quit
|
||||||
|
|
||||||
Saves and closes the current session and terminates the server.
|
Saves and closes the current session and terminates the server.
|
||||||
|
|
||||||
= /nsm/server/duplicate s:new_project
|
|
||||||
Saves and closes the current session, creates a complete copy of
|
|
||||||
it as `new_project` and opens it. The existing project should ideally be
|
|
||||||
a lightweight template, as copying any audio data could be very time
|
|
||||||
consuming.
|
|
||||||
|
|
||||||
= /nsm/server/list
|
= /nsm/server/list
|
||||||
|
|
||||||
Lists available projects. One `\/reply` message will be sent for each existing project.
|
Lists available projects. One `\/reply` message will be sent for each existing project.
|
||||||
|
|
||||||
:::: Client to Client Communication
|
:::: Client to Client Communication
|
||||||
|
|
|
@ -3,17 +3,17 @@
|
||||||
<meta name="generator" content="Generated by MUP v3.5">
|
<meta name="generator" content="Generated by MUP v3.5">
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
<link type="text/css" rel="stylesheet" href="mup.css">
|
<link type="text/css" rel="stylesheet" href="mup.css">
|
||||||
<title></title>
|
<title>Non Session Manager User Manual</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id=cover>
|
<div id=cover>
|
||||||
<h1></h1>
|
<h1>Non Session Manager User Manual</h1>
|
||||||
<h3></h3>
|
<h3></h3>
|
||||||
<address>
|
<address>
|
||||||
<br>
|
Jonathan Moore Liles <a href="mailto:male@tuxfamily.org"><male@tuxfamily.org></a><br>
|
||||||
<br>
|
February 25, 2012<br>
|
||||||
|
|
||||||
</address><hr></div>
|
</address><img src="icon.png" alt="logo"><hr></div>
|
||||||
<div id=body>
|
<div id=body>
|
||||||
<div id=toc>
|
<div id=toc>
|
||||||
<h1 id=toc>Table Of Contents</h1>
|
<h1 id=toc>Table Of Contents</h1>
|
||||||
|
@ -39,13 +39,15 @@
|
||||||
|
|
||||||
</ul><li><a href="#n:1.1.2.">1.1.2. Removing a Client From a Session</a>
|
</ul><li><a href="#n:1.1.2.">1.1.2. Removing a Client From a Session</a>
|
||||||
|
|
||||||
</ul><li><a href="#n:1.2.">1.2. The NSM Daemon</a>
|
</ul><li><a href="#n:1.2.">1.2. Saving and Restoring Aspects of the Environment</a>
|
||||||
|
|
||||||
<ul><li><a href="#n:1.2.1.">1.2.1. Multiple NSMD Instance</a>
|
<li><a href="#n:1.3.">1.3. The NSM Daemon</a>
|
||||||
|
|
||||||
<ul><li><a href="#n:1.2.1.1.">1.2.1.1. Distributed Session Management</a>
|
<ul><li><a href="#n:1.3.1.">1.3.1. Multiple NSMD Instances</a>
|
||||||
|
|
||||||
<li><a href="#n:1.2.1.2.">1.2.1.2. Multiple Sessions On One Host</a>
|
<ul><li><a href="#n:1.3.1.1.">1.3.1.1. Distributed Session Management</a>
|
||||||
|
|
||||||
|
<li><a href="#n:1.3.1.2.">1.3.1.2. Multiple Sessions On One Host</a>
|
||||||
|
|
||||||
</ul></ul></ul></ul></ul><hr></div>
|
</ul></ul></ul></ul></ul><hr></div>
|
||||||
<h1 id="n:1.">1. User Manual</h1>
|
<h1 id="n:1.">1. User Manual</h1>
|
||||||
|
@ -79,13 +81,16 @@ All session data is stored in per-session sub-directories of the <i>Session Root
|
||||||
There are two ways to open a session.
|
There are two ways to open a session.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The first is to click the Open button and type in the exact name of an existing session. The second is to click on the desired session name in the session list panel in the left hand half of the interface. Either way, opening a session saves the current session and switches to the new one. Clients which are capable of switching projects without restarting are instructed to do so, resulting in very fast session open times when such clients are participating in both sessions.
|
The first is to click the <i>Open</i> button and type in the exact name of an existing session. The second is to click on the desired session name in the session list panel on the left side of the interface.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Either way, opening a session saves the current session and switches to the new one. Clients which are capable of switching projects without restarting are instructed to do so, resulting in very fast session open times when such clients are participating in both sessions.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Clients cannot be added until a session is open, either by <i>Open</i> or <i>New</i>.
|
Clients cannot be added until a session is open, either by <i>Open</i> or <i>New</i>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
As each client launches, a status bar representing it will be added to the client list in the hand panel of the interface. For clients which are capable of reporting their progress, a progress bar will also become active.
|
As each client launches, a status bar representing it will be added to the client list on the right half the interface. For clients which are capable of reporting their progress, a progress bar will also become active.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Only clients supporting the NSM protocol can be told what to open and when to save. Clients not supporting NSM may still be added to the session, but their behavior is undefined other than that NSM can invoke and kill them.
|
Only clients supporting the NSM protocol can be told what to open and when to save. Clients not supporting NSM may still be added to the session, but their behavior is undefined other than that NSM can invoke and kill them.
|
||||||
|
@ -128,22 +133,32 @@ Templates are supported in by the Non Session Manager via duplication. Clicking
|
||||||
Obviously, this should be avoided for sessions containing audio data, as the copy would be very time consuming.
|
Obviously, this should be avoided for sessions containing audio data, as the copy would be very time consuming.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
To create a template in the first place, simply use <i>New</i> to start a new session (preferably with a name beginning with Template/), add the desired clients to it, and configure them (e.g. add plugins, make JACK connections, etc.) Now, any time you want to start a session from that template, simply switch to the template session and click <i>Duplicate</i> to create a new session based on it.
|
To create a template in the first place, simply use <i>New</i> to start a new session (preferably with a name beginning with "Templates/"), add the desired clients to it, and configure them (e.g. add plugins, make JACK connections, etc.) Now, any time you want to start a session from that template, simply switch to the template session and click <i>Duplicate</i> to create a new session based on it.
|
||||||
</p>
|
</p>
|
||||||
<h4 id="n:1.1.1.7.">1.1.1.7. Add Client</h4>
|
<h4 id="n:1.1.1.7.">1.1.1.7. Add Client</h4>
|
||||||
<p>
|
<p>
|
||||||
This option will prompt the user for the executable name of the client to be added to the session. It is not necessary to type the full path (the PATH environment variable will be searched to find the executable).
|
This option will prompt the user for the executable name of the client to be added to the session. It is not necessary to type the full path (the PATH environment variable will be searched to find the executable).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When controlling an NSM session distributed across multiple machines, the user will also be required to choose which server to invoke the client on.
|
||||||
</p>
|
</p>
|
||||||
<h3 id="n:1.1.2.">1.1.2. Removing a Client From a Session</h3>
|
<h3 id="n:1.1.2.">1.1.2. Removing a Client From a Session</h3>
|
||||||
<p>
|
<p>
|
||||||
If a client dies unexpectedly or is closed by the user (e.g. by closing its main window), Non Session Manager will detect this and two buttons will appear on that Client's status bar. One button, the arrow, causes the client to be restarted, and to reopen its project file where it left off. The <i>X</i> button causes the client to be permanently removed from the session.
|
If a client dies unexpectedly or is closed by the user (e.g. by closing its main window), Non Session Manager will detect this and two buttons will appear on that Client's status bar. One button, the arrow, causes the client to be restarted and to reopen its project file where it left off. The <i>X</i> button causes the client to be permanently removed from the session.
|
||||||
</p>
|
</p>
|
||||||
<h2 id="n:1.2.">1.2. The NSM Daemon</h2>
|
<h2 id="n:1.2.">1.2. Saving and Restoring Aspects of the Environment</h2>
|
||||||
<p>
|
<p>
|
||||||
The NSM Daemon (nsmd) is launched automatically by the Non Session Manager interface whenever one is not found to be already running at the URL specified in the environment
|
NSM manages clients together in a session. That's it. NSM doesn't know or care what Window Manager or audio subsystem those clients use--nor should it. Specific clients must be written to persist these environmental factors, and added to sessions when required.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Users who are not attempting setup advanced modes like shared sessions between machines will not normally need to even know that <tt>nsmd</tt> is running.
|
For saving and restoring the JACK connection graph, a simple headless client named <tt>jackpatch</tt> has been developed and included in the NSM distribution. Simply add <tt>jackpatch</tt> do your basic template session and all the sessions you base on it will have their JACK connection graphs automatically saved and restored.
|
||||||
|
</p>
|
||||||
|
<h2 id="n:1.3.">1.3. The NSM Daemon</h2>
|
||||||
|
<p>
|
||||||
|
The NSM Daemon (nsmd) is launched automatically by the Non Session Manager interface whenever one is not found to be already running at the URL specified in the environment.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Users who are not attempting to setup advanced modes like shared sessions between machines will not normally need to even know that <tt>nsmd</tt> is running.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
But for those advanced users, here are the command-line options for launching nsmd separately from the GUI.
|
But for those advanced users, here are the command-line options for launching nsmd separately from the GUI.
|
||||||
|
@ -153,13 +168,13 @@ nsmd [--session-root path] [--osc-port port] [--detach]
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
</table></div>
|
</table></div>
|
||||||
<p>
|
<p>
|
||||||
The <tt>--session-root</tt> option allows one to override default <i>Session Root</i> is "$HOME/NSM Sessions" (this option can also be passed to the GUI, which will hand it over to the daemon).
|
The <tt>--session-root</tt> option allows one to override where <i>Session Root</i> is, from the default of "$HOME/NSM Sessions" (this option can also be passed to the GUI, which will hand it over to the daemon).
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<tt>--osc-port</tt> instructs the daemon to bind to a specific UDP port number instead of selecting an available port automatically.
|
<tt>--osc-port</tt> instructs the daemon to bind to a specific UDP port number instead of selecting an available port automatically.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<tt>--detach</tt> instructs the daemon to close its standard input and output and go completely into the background. This is useful for starting the daemon remotely with <tt>rsh</tt>.
|
<tt>--detach</tt> instructs the daemon to close its standard input and output and go into the background. This is useful for starting the daemon remotely with <tt>rsh</tt>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
When nsmd starts, it will print a string of the following form its standard output.
|
When nsmd starts, it will print a string of the following form its standard output.
|
||||||
|
@ -169,27 +184,27 @@ NSM_URL=osc.udp://foo.bar.net:17551/
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
</table></div>
|
</table></div>
|
||||||
<p>
|
<p>
|
||||||
This is the OSC URL for the daemon process. If this URL is included in the environment (by either using a fixed port number or starting nsmd early in the initialization process [like in your .xinitrc] extracting the URL from its output.) then any NSM capable client will join the current session when started, even if started from outside the Non Session Manager interface (e.g. by your desktop environment's program launch menu).
|
This is the OSC URL for the daemon process. If this URL is included in the environment (by either using a fixed port number or starting nsmd early in the initialization process [like in your .xinitrc] extracting the URL from its output) then any NSM capable client will join the current session when started, even if started from outside the Non Session Manager interface (for example, by your Desktop Environment's program launch menu).
|
||||||
</p>
|
</p>
|
||||||
<h3 id="n:1.2.1.">1.2.1. Multiple NSMD Instance</h3>
|
<h3 id="n:1.3.1.">1.3.1. Multiple NSMD Instances</h3>
|
||||||
<p>
|
<p>
|
||||||
When dealing with multiple instances of nsmd, whether they be on the same machine or different machines, it is most convenient to use fixed port numbers.
|
When dealing with multiple instances of nsmd, whether they be on the same host or separate hosts, it is most convenient to use fixed port numbers specified with the <tt>--osc-port</tt> command-line option.
|
||||||
</p>
|
</p>
|
||||||
<h4 id="n:1.2.1.1.">1.2.1.1. Distributed Session Management</h4>
|
<h4 id="n:1.3.1.1.">1.3.1.1. Distributed Session Management</h4>
|
||||||
<p>
|
<p>
|
||||||
In some situations it is necessary to have different audio programs running on different machines connected by S/PDIF/or analog wiring or over TCP/IP as achieved by <tt>netjack</tt>. Usually the reason for doing this is that neither machine is powerful enough to do all the DSP or synthesis by itself.
|
In some situations it is necessary to have different audio programs running on different machines, connected by S/PDIF, analog wiring, or over TCP/IP as achieved by <tt>netjack</tt>. Usually the reason for doing this is that neither machine is powerful enough to do all the DSP or synthesis alone.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Needless to say, these configurations have historically been extremely difficult to manage--requiring heavy scripting or lots of manual setup.
|
Needless to say, these configurations have historically been extremely difficult to manage--requiring heavy scripting and/or lots of manual setup.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
NSM is the first and currently only system capable of managing these sessions.
|
NSM is the first--and currently only--system capable of managing these sessions.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Let us assume the following conditions for our example:
|
Let us assume the following conditions for our example:
|
||||||
</p>
|
</p>
|
||||||
<ol><li><span>We want to distribute a session across two hosts, Host-A and Host-B, on the local area network</span>
|
<ol><li><span>We want to distribute a session across two hosts, Host-A and Host-B, on the local area network.</span>
|
||||||
<li><span>Each host has a completely independent file system (i.e. not NFS)</span>
|
<li><span>Each host has a completely independent file system (i.e. not NFS).</span>
|
||||||
<li><span>We have appropriate access to both hosts.</span>
|
<li><span>We have appropriate access to both hosts.</span>
|
||||||
</ol><p>
|
</ol><p>
|
||||||
The first step is to decide what port numbers to use. Let's choose <tt>6661</tt> for Host-A and <tt>6662</tt> for Host-B.
|
The first step is to decide what port numbers to use. Let's choose <tt>6661</tt> for Host-A and <tt>6662</tt> for Host-B.
|
||||||
|
@ -224,12 +239,12 @@ user@host-a:~$ non-session-manager --nsm-url osc.udp://host-a:6661 --nsm-url osc
|
||||||
<p>
|
<p>
|
||||||
The Non Session Manager interface will then connect to the daemons on both hosts. Creating a new session will create separate session files on each host. When adding a client, the interface will present the user with a choice of which host to invoke the client on. Aside from that it is just like managing any other session. Sessions can be opened, saved, switched between, etc. and the desired effect will be seen on each host.
|
The Non Session Manager interface will then connect to the daemons on both hosts. Creating a new session will create separate session files on each host. When adding a client, the interface will present the user with a choice of which host to invoke the client on. Aside from that it is just like managing any other session. Sessions can be opened, saved, switched between, etc. and the desired effect will be seen on each host.
|
||||||
</p>
|
</p>
|
||||||
<h4 id="n:1.2.1.2.">1.2.1.2. Multiple Sessions On One Host</h4>
|
<h4 id="n:1.3.1.2.">1.3.1.2. Multiple Sessions On One Host</h4>
|
||||||
<p>
|
<p>
|
||||||
Simply starting two (or more) instances of the Non Session Manager interface on the same machine (when the NSM_URL environment variable is unset) will result in the ability to have two different sessions open at the same time on the same host. The instances are prohibited from opening two instances of the same session.
|
Simply starting two (or more) instances of the Non Session Manager interface on the same machine (when the NSM_URL environment variable is unset) will result in the ability to have two different sessions open at the same time on the same host. A lock file prevents the two instances from opening the same session.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Imagining a useful application of this feature is left as an exercise for the user.
|
Imagining a useful application of this feature is left as an exercise for the reader.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
|
||||||
! title The Non Session Manager User Manual
|
! title Non Session Manager User Manual
|
||||||
! author Jonathan Moore Liles #(email,male@tuxfamily.org)
|
! author Jonathan Moore Liles #(email,male@tuxfamily.org)
|
||||||
! date February 25, 2012
|
! date February 25, 2012
|
||||||
|
! extra #(image,logo,icon.png)
|
||||||
|
|
||||||
-- Table Of Contents
|
-- Table Of Contents
|
||||||
|
|
||||||
|
@ -33,11 +34,11 @@
|
||||||
|
|
||||||
There are two ways to open a session.
|
There are two ways to open a session.
|
||||||
|
|
||||||
The first is to click the Open button and type in the exact name of
|
The first is to click the /Open/ button and type in the exact name
|
||||||
an existing session. The second is to click on the desired session
|
of an existing session. The second is to click on the desired
|
||||||
name in the session list panel in the left hand half of the
|
session name in the session list panel on the left side of the
|
||||||
interface.
|
interface.
|
||||||
|
|
||||||
Either way, opening a session saves the current session and switches
|
Either way, opening a session saves the current session and switches
|
||||||
to the new one. Clients which are capable of switching projects
|
to the new one. Clients which are capable of switching projects
|
||||||
without restarting are instructed to do so, resulting in very fast
|
without restarting are instructed to do so, resulting in very fast
|
||||||
|
@ -48,7 +49,7 @@
|
||||||
/New/.
|
/New/.
|
||||||
|
|
||||||
As each client launches, a status bar representing it will be added
|
As each client launches, a status bar representing it will be added
|
||||||
to the client list in the hand panel of the interface. For clients
|
to the client list on the right half the interface. For clients
|
||||||
which are capable of reporting their progress, a progress bar will
|
which are capable of reporting their progress, a progress bar will
|
||||||
also become active.
|
also become active.
|
||||||
|
|
||||||
|
@ -108,8 +109,8 @@
|
||||||
data, as the copy would be very time consuming.
|
data, as the copy would be very time consuming.
|
||||||
|
|
||||||
To create a template in the first place, simply use /New/ to start a
|
To create a template in the first place, simply use /New/ to start a
|
||||||
new session (preferably with a name beginning with Template\/), add
|
new session (preferably with a name beginning with "Templates\/"),
|
||||||
the desired clients to it, and configure them (e.g. add plugins,
|
add the desired clients to it, and configure them (e.g. add plugins,
|
||||||
make JACK connections, etc.)
|
make JACK connections, etc.)
|
||||||
|
|
||||||
Now, any time you want to start a session from that template, simply
|
Now, any time you want to start a session from that template, simply
|
||||||
|
@ -121,24 +122,42 @@
|
||||||
This option will prompt the user for the executable name of the
|
This option will prompt the user for the executable name of the
|
||||||
client to be added to the session. It is not necessary to type the
|
client to be added to the session. It is not necessary to type the
|
||||||
full path (the PATH environment variable will be searched to find
|
full path (the PATH environment variable will be searched to find
|
||||||
the executable).
|
the executable).
|
||||||
|
|
||||||
|
When controlling an NSM session distributed across multiple
|
||||||
|
machines, the user will also be required to choose which server to
|
||||||
|
invoke the client on.
|
||||||
|
|
||||||
::: Removing a Client From a Session
|
::: Removing a Client From a Session
|
||||||
|
|
||||||
If a client dies unexpectedly or is closed by the user (e.g. by
|
If a client dies unexpectedly or is closed by the user (e.g. by
|
||||||
closing its main window), Non Session Manager will detect this and
|
closing its main window), Non Session Manager will detect this and
|
||||||
two buttons will appear on that Client's status bar. One button, the
|
two buttons will appear on that Client's status bar. One button, the
|
||||||
arrow, causes the client to be restarted, and to reopen its project
|
arrow, causes the client to be restarted and to reopen its project
|
||||||
file where it left off. The /X/ button causes the client to be
|
file where it left off. The /X/ button causes the client to be
|
||||||
permanently removed from the session.
|
permanently removed from the session.
|
||||||
|
|
||||||
|
|
||||||
|
:: Saving and Restoring Aspects of the Environment
|
||||||
|
|
||||||
|
NSM manages clients together in a session. That's it. NSM doesn't
|
||||||
|
know or care what Window Manager or audio subsystem those clients
|
||||||
|
use--nor should it. Specific clients must be written to persist
|
||||||
|
these environmental factors, and added to sessions when required.
|
||||||
|
|
||||||
|
For saving and restoring the JACK connection graph, a simple
|
||||||
|
headless client named `jackpatch` has been developed and included in
|
||||||
|
the NSM distribution. Simply add `jackpatch` do your basic template
|
||||||
|
session and all the sessions you base on it will have their JACK
|
||||||
|
connection graphs automatically saved and restored.
|
||||||
|
|
||||||
:: The NSM Daemon
|
:: The NSM Daemon
|
||||||
|
|
||||||
The NSM Daemon (nsmd) is launched automatically by the Non Session
|
The NSM Daemon (nsmd) is launched automatically by the Non Session
|
||||||
Manager interface whenever one is not found to be already running at
|
Manager interface whenever one is not found to be already running at
|
||||||
the URL specified in the environment
|
the URL specified in the environment.
|
||||||
|
|
||||||
Users who are not attempting setup advanced modes like shared
|
Users who are not attempting to setup advanced modes like shared
|
||||||
sessions between machines will not normally need to even know that
|
sessions between machines will not normally need to even know that
|
||||||
`nsmd` is running.
|
`nsmd` is running.
|
||||||
|
|
||||||
|
@ -147,16 +166,16 @@
|
||||||
|
|
||||||
> nsmd [--session-root path] [--osc-port port] [--detach]
|
> nsmd [--session-root path] [--osc-port port] [--detach]
|
||||||
|
|
||||||
The `--session-root` option allows one to override default /Session
|
The `--session-root` option allows one to override where /Session
|
||||||
Root/ is "$HOME\/NSM Sessions" (this option can also be passed to the
|
Root/ is, from the default of "$HOME\/NSM Sessions" (this option can
|
||||||
GUI, which will hand it over to the daemon).
|
also be passed to the GUI, which will hand it over to the daemon).
|
||||||
|
|
||||||
`--osc-port` instructs the daemon to bind to a specific UDP port
|
`--osc-port` instructs the daemon to bind to a specific UDP port
|
||||||
number instead of selecting an available port automatically.
|
number instead of selecting an available port automatically.
|
||||||
|
|
||||||
`--detach` instructs the daemon to close its standard input and
|
`--detach` instructs the daemon to close its standard input and
|
||||||
output and go completely into the background. This is useful for
|
output and go into the background. This is useful for starting the
|
||||||
starting the daemon remotely with `rsh`.
|
daemon remotely with `rsh`.
|
||||||
|
|
||||||
When nsmd starts, it will print a string of the following form its
|
When nsmd starts, it will print a string of the following form its
|
||||||
standard output.
|
standard output.
|
||||||
|
@ -166,37 +185,36 @@
|
||||||
This is the OSC URL for the daemon process. If this URL is included
|
This is the OSC URL for the daemon process. If this URL is included
|
||||||
in the environment (by either using a fixed port number or starting
|
in the environment (by either using a fixed port number or starting
|
||||||
nsmd early in the initialization process [like in your .xinitrc]
|
nsmd early in the initialization process [like in your .xinitrc]
|
||||||
extracting the URL from its output.) then any NSM capable client
|
extracting the URL from its output) then any NSM capable client will
|
||||||
will join the current session when started, even if started from
|
join the current session when started, even if started from outside
|
||||||
outside the Non Session Manager interface (e.g. by your desktop
|
the Non Session Manager interface (for example, by your Desktop
|
||||||
environment's program launch menu).
|
Environment's program launch menu).
|
||||||
|
|
||||||
|
::: Multiple NSMD Instances
|
||||||
::: Multiple NSMD Instance
|
|
||||||
|
|
||||||
When dealing with multiple instances of nsmd, whether they be on the
|
When dealing with multiple instances of nsmd, whether they be on the
|
||||||
same machine or different machines, it is most convenient to use
|
same host or separate hosts, it is most convenient to use fixed port
|
||||||
fixed port numbers.
|
numbers specified with the `--osc-port` command-line option.
|
||||||
|
|
||||||
:::: Distributed Session Management
|
:::: Distributed Session Management
|
||||||
|
|
||||||
In some situations it is necessary to have different audio programs
|
In some situations it is necessary to have different audio programs
|
||||||
running on different machines connected by S\/PDIF\/or analog wiring
|
running on different machines, connected by S\/PDIF, analog wiring,
|
||||||
or over TCP\/IP as achieved by `netjack`. Usually the reason for
|
or over TCP\/IP as achieved by `netjack`. Usually the reason for
|
||||||
doing this is that neither machine is powerful enough to do all the
|
doing this is that neither machine is powerful enough to do all the
|
||||||
DSP or synthesis by itself.
|
DSP or synthesis alone.
|
||||||
|
|
||||||
Needless to say, these configurations have historically been
|
Needless to say, these configurations have historically been
|
||||||
extremely difficult to manage--requiring heavy scripting or lots of
|
extremely difficult to manage--requiring heavy scripting and\/or
|
||||||
manual setup.
|
lots of manual setup.
|
||||||
|
|
||||||
NSM is the first and currently only system capable of managing these
|
NSM is the first--and currently only--system capable of managing
|
||||||
sessions.
|
these sessions.
|
||||||
|
|
||||||
Let us assume the following conditions for our example:
|
Let us assume the following conditions for our example:
|
||||||
|
|
||||||
+ We want to distribute a session across two hosts, Host-A and Host-B, on the local area network
|
+ We want to distribute a session across two hosts, Host-A and Host-B, on the local area network.
|
||||||
+ Each host has a completely independent file system (i.e. not NFS)
|
+ Each host has a completely independent file system (i.e. not NFS).
|
||||||
+ We have appropriate access to both hosts.
|
+ We have appropriate access to both hosts.
|
||||||
|
|
||||||
The first step is to decide what port numbers to use. Let's choose
|
The first step is to decide what port numbers to use. Let's choose
|
||||||
|
@ -234,8 +252,9 @@
|
||||||
Simply starting two (or more) instances of the Non Session Manager
|
Simply starting two (or more) instances of the Non Session Manager
|
||||||
interface on the same machine (when the NSM\_URL environment
|
interface on the same machine (when the NSM\_URL environment
|
||||||
variable is unset) will result in the ability to have two different
|
variable is unset) will result in the ability to have two different
|
||||||
sessions open at the same time on the same host. The instances are
|
sessions open at the same time on the same host. A lock file
|
||||||
prohibited from opening two instances of the same session.
|
prevents the two instances from opening the same session.
|
||||||
|
|
||||||
Imagining a useful application of this feature is left as an
|
Imagining a useful application of this feature is left as an
|
||||||
exercise for the user.
|
exercise for the reader.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue