<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<base href="https://wiki.asterisk.org/wiki" />
<title>Message Title</title>
<style type="text/css">@media only screen and (max-device-width: 480px) {.mobile-only {
width: auto !important;
height: auto !important;
overflow: visible !important;
line-height: normal !important;
font-size: inherit !important;
mso-hide: all;
}
.desktop-only {
display: none !important;
}
/* iPhone 3GS fix for unwanted 20px right margin */
body { min-width: 100% !important; padding: 0; margin: 0; }
#center-content-table { max-width: none; !important; }
#header-pattern-container { padding: 10px 10px 10px 10px !important; line-height: 20px !important; }
#header-avatar-image-container { padding-right: 8px !important; }
#email-content-container { padding: 0 !important; }
.mobile-expand { border-radius: 0 !important; border-left: 0 !important; border-right: 0 !important; padding-left: 26px !important;}
.mobile-resize-text { font-size: 16px !important; line-height: 22px !important; }
#page-title-pattern-header { font-size: 20px !important; line-height: 28px !important; }
#page-title-pattern-icon-image-container-cell { padding-top: 7px !important; }
#inline-user-pattern { display: block !important; }
#inline-user-pattern-avatar { padding-top: 3px !important; }
.contextual-area-pattern { border-bottom: 1px solid #ccc !important; padding: 15px 10px 0 10px !important;}
.users-involved-pattern-column-table { width: 100% !important; }
.users-involved-pattern-avatar-table-cell { padding: 3px 5px 5px 0 !important; }
.users-involved-pattern-column-container { padding-right: 0 !important; }
.contextual-excerpt-pattern, #users-involved-pattern { border: 0 !important; }
/** Aui Typography upsized for mobile **/
#content-excerpt-pattern-container, #contextual-excerpt-pattern-text-container { font-size: 16px !important; line-height: 22px !important; }
#content-excerpt-pattern-container h1, #contextual-excerpt-pattern-text-container h1 { font-size: 24px !important; line-height: 28px !important; }
#content-excerpt-pattern-container h2, #contextual-excerpt-pattern-text-container h2 { font-size: 20px !important; line-height: 28px !important; }
#content-excerpt-pattern-container h3, #contextual-excerpt-pattern-text-container h3 { font-size: 18px !important; line-height: 24px !important; }
#content-excerpt-pattern-container h4, #contextual-excerpt-pattern-text-container h4 { font-size: 16px !important; line-height: 22px !important; }
#content-excerpt-pattern-container h5, #contextual-excerpt-pattern-text-container h5 { font-size: 14px !important; line-height: 20px !important; }
#content-excerpt-pattern-container h6, #contextual-excerpt-pattern-text-container h6 { font-size: 14px !important; line-height: 20px !important; }
.user-mention { line-height: 18px !important; }
/** Aui Typography end **/
/* Show appropriate footer logo on mobile, display links vertically */
#footer-pattern { padding: 15px 10px !important; }
#footer-pattern-logo-desktop-container { padding: 0 !important; }
#footer-pattern-logo-desktop { width: 0 !important; height: 0 !important; }
#footer-pattern-logo-mobile {
padding-top: 10px !important;
width: 30px !important;
height: 27px !important;
display: inline !important;
}
#footer-pattern-text {
display: block !important;
}
#footer-pattern-links-container { line-height: 0 !important;}
.footer-pattern-links.mobile-resize-text,
.footer-pattern-links.mobile-resize-text,
#footer-pattern-text.mobile-resize-text,
#footer-pattern-links-container.no-footer-links {
font-size: 14px !important;
line-height: 20px !important;
}
.footer-link { display: block !important; }
#footer-pattern-links-container table { display: inline-block !important; float: none !important; }
#footer-pattern-links-container, #footer-pattern-text { text-align: center !important; }
#footer-pattern-links { padding-bottom: 5px !important; }
/** Team Calendar overrides, these should be removed when notifications are updated in Team Calendars. For now CSS
overrides are being used because the structure of the content can't change without rereleasing the plugin */
.mail-calendar-container .day-header + table tr td:first-child {
vertical-align: top !important;
padding-top: 5px !important;
}}
@media (min-width: 900px) {#center-content-table { width: 900px; }}
@media all {#outlook a {padding:0;} /* Force Outlook to provide a "view in browser" menu link. */
/* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/
body{-webkit-text-size-adjust:100%; -ms-text-size-adjust:100%;}
.ExternalClass {width:100%;} /* Force Hotmail to display emails at full width */
#background-table {margin:0; padding:0; width:100% !important; }
/* Needed to override highlighting on date and time links in iOS */
.grey a {color: #707070; text-decoration: none; }/* These styles are appended to the head element of a notification in order to prevent Apple Mail and similar
clients from underlining the due dates with a blue hyperlink */
/* a lozenge outside an inline task should always be #333, lozenges inside an inline task should be
colored according to their upcoming due dates, a completed task date lozenge or deleted task date
lozenge should always be #707070 */
.date-time-lozenge a {color: #333333; text-decoration: none; }
.inline-task-text-container .date-time-lozenge.date-upcoming a {color: #DF6F00; text-decoration: none; }
.inline-task-text-container .date-time-lozenge.date-past a {color: #D04437; text-decoration: none; }
.inline-task-text-container.content-deleted-color .date-time-lozenge a,
.inline-task-text-container.checked .date-time-lozenge a {
color: #707070; text-decoration: none;
}}
</style>
</head>
<body>
<table id="background-table" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; background-color: #f5f5f5">
<tbody>
<tr>
<td id="header-pattern-container" style="padding: 0px; border-collapse: collapse; padding: 10px 20px">
<table id="header-pattern" cellspacing="0" cellpadding="0" border="0" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td id="header-avatar-image-container" valign="top" style="padding: 0px; border-collapse: collapse; vertical-align: top; width: 32px; padding-right: 9px"><a href="https://wiki.asterisk.org/wiki/display/~jcolp?src=email" style="color: #3b73af; text-decoration: none"><img id="header-avatar-image" class="image_fix" src="cid:avatar_72d18d2d9f6a7c208e7edb4531f793b7" height="32" width="32" border="0" style="border-radius: 3px; vertical-align: top" /></a></td>
<td id="header-text-container" valign="middle" style="padding: 0px; border-collapse: collapse; vertical-align: middle; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 1px">Joshua C. Colp <strong>edited</strong> a page</td>
</tr>
</tbody>
</table> </td>
</tr>
<!-- End Header pattern -->
<tr>
<td id="email-content-container" style="padding: 0px; border-collapse: collapse; padding: 0 20px">
<table id="email-content-table" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; border-spacing: 0; border-collapse: separate">
<tbody>
<tr>
<td class="email-content-rounded-top mobile-expand" style="padding: 0px; border-collapse: collapse; color: #fff; padding: 0 15px 0 16px; height: 15px; background-color: #fff; border-left: 1px solid #ccc; border-top: 1px solid #ccc; border-right: 1px solid #ccc; border-bottom: 0; border-top-right-radius: 5px; border-top-left-radius: 5px"> </td>
</tr>
<tr>
<td class="email-content-main mobile-expand" style="padding: 0px; border-collapse: collapse; border-left: 1px solid #ccc; border-right: 1px solid #ccc; border-top: 0; border-bottom: 0; padding: 0 15px 15px 16px; background-color: #fff">
<table id="page-title-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td id="page-title-pattern-icon-image-container" valign="top" style="padding: 0px; border-collapse: collapse; width: 16px; vertical-align: top">
<table cellspacing="0" cellpadding="0" border="0" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td id="page-title-pattern-icon-image-container-cell" style="padding: 0px; border-collapse: collapse; width: 16px; padding: 9px 8px 0px 0px; mso-text-raise: 5px; mso-line-height-rule: exactly"><a href="https://wiki.asterisk.org/wiki/display/AST/Stasis+Message+Bus?src=email" title="page icon" style="vertical-align: top;; color: #3b73af; text-decoration: none"><img style="vertical-align: top; display: block;" src="cid:page-icon" alt="page icon" title="page icon" height="16" width="16" border="0" /></a></td>
</tr>
</tbody>
</table> </td>
<td style="vertical-align: top;; padding: 0px; border-collapse: collapse; padding-right: 5px; font-size: 20px; line-height: 30px; mso-line-height-rule: exactly" id="page-title-pattern-header-container"><span id="page-title-pattern-header" style="font-family: Arial, sans-serif; padding: 0; font-size: 20px; line-height: 30px; mso-text-raise: 2px; mso-line-height-rule: exactly; vertical-align: middle"><a href="https://wiki.asterisk.org/wiki/display/AST/Stasis+Message+Bus?src=email" title="Stasis Message Bus" style="color: #3b73af; text-decoration: none">Stasis Message Bus</a></span></td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td class="email-content-main mobile-expand" style="padding: 0px; border-collapse: collapse; border-left: 1px solid #ccc; border-right: 1px solid #ccc; border-top: 0; border-bottom: 0; padding: 0 15px 15px 16px; background-color: #fff">
<table class="content-excerpt-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 1px">
<tbody>
<tr>
<td class="content-excerpt-pattern-container mobile-resize-text " style="padding: 0px; border-collapse: collapse; padding: 0 0 0 24px"> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0; margin-top: 0"></p>
<table class="diff-macro diff-html-changed" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<thead>
<tr>
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="diff-html-changed" id="changed-diff-0" style="background-color: #d6f0ff;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5639/a252d7f5e75d7a8bf7047b4b2c92f71a56a8f048.48/_/images/icons/macrobrowser/macro-placeholder-default.png" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Wiki Markup</span></th>
</tr>
</thead>
<tbody>
<tr>
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <pre style="margin: 10px 0 0 0; margin-top: 0">
<span class="diff-html-changed" style="background-color: #d6f0ff;">{numberedheadings}
While the basic API's for the Stasis Message Bus are </span>
</pre> </td>
</tr>
</tbody>
</table> <p style="margin: 10px 0 0 0"></p> <p class="diff-context-placeholder" style="margin: 10px 0 0 0">...</p> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"></p>
<table class="diff-macro" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <pre style="margin: 10px 0 0 0; margin-top: 0">
<span class="diff-html-changed" id="changed-diff-1" style="background-color: #d6f0ff;">documented using Doxygen</span>
</pre> </td>
</tr>
</tbody>
</table> <p style="margin: 10px 0 0 0"></p> <p class="diff-context-placeholder" style="margin: 10px 0 0 0">...</p> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"></p>
<table class="diff-macro" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <pre style="margin: 10px 0 0 0; margin-top: 0">
<span class="diff-html-changed" id="changed-diff-2" style="background-color: #d6f0ff;">, there's still a lot to be said about how to use those API's within Asterisk.
{toc:style=none}
h1. Message Bus
The overall stasis-core API can be best described as a publish/subscribe message bus.
Data that needs to be published on the message bus is encapsulated in a {{stasis_message}}, which associates the message data (which is simply an AO2 managed {{void *}}) along with a {{stasis_message_type}}. (The message also has the {{timeval}} when it was created, which is generally useful, since messages are received asynchronously).
Messages are published to a {{stasis_topic}}. To receive the messages published to a topic, use {{stasis_subscribe()}} to create a subscription.
When topics are subscribed to/unsubscribed to, {{stasis_subscription_change}} are sent to all of the topic's subscribers. On unsubscribe, the {{stasis_subscription_change}} will be the last message received by the unsubscriber, which can be used to kick off any cleanup that might be necessary. The convenience function {{stasis_subscription_final_message()}} can be used to check if a message is the final unsubscribe message.
To forward all of the messages from one topic to another, use {{stasis_forward_all()}}. This is useful for creating aggregation topics, like {{[ast_channel_topic_all()|#ast_channel_topic_all()]}}, which collect all of the messages published to a set of other topics.
h2. Routing and Caching
In addition to these fundamental concepts, there are a few extra objects in the Stasis Message Bus arsenal.
For subscriptions that deal with many different types of messages, the {{stasis_message_router}} can be used to route messages based on type. This gets rid of a lot of ugly looking {{if/else}} chains and replaces them with callback dispatch.
Another common use case within Asterisk is to have a subscription that monitors state changes for snapshots that are published to a topic. To aid in this, we have {{stasis_caching_topic}}. This is a _topic filter_, which presents its own topic with filtered and modified messages from an original topic. In the case of the caching topic, it watches for snapshot messages, compares them with their prior values. For these messages, it publishes a {{stasis_cache_update}} message with both the old and new values of the snapshot.
h2. Design Philosophy
By convention (since there's no effective way to enforce this in C), messages are immutable. Not only the {{stasis_message}} type itself, but also the data it contains. This allows messages to be shared freely throughout the system without locking. If you find yourself in the situation where you want to modify the contents of a {{stasis_message}}, what you actually want to do is copy the message, and change the copy. While on the surface this seems wasteful and inefficient, the gains in reducing lock contention win the day.
Messages are opaque to the message bus, so you don't have to modify {{stasis.c}} or {{stasis.h}} to add a new topic or message type.
The {{stasis_topic}} object is thread safe. Subscribes, unsubscribes and publishes may happen from any thread. There are some ordering guarantees about message delivery, but not many.
* A {{stasis_publish()}} that begins after a {{stasis_publish()}} to the same topic completes will be delivered in order.
** In general, this means that publications from different threads to the same topic are unordered, but publications from the same thread are.
* Publications to different topics are not ordered.
* The final message delivered to a subscription will be the {{stasis_subscription_final_message()}}.
The callback invocations for a {{stasis_topic}} are serialized, although invocations can happen out of any thread from the Stasis thread pool. This is a comfortable middle ground between allocating a thread for every subscription (which would result in too many threads in the system) and invoking callbacks in parallel (which can cause insanity). If your particular handling can benefit from being parallelized, then you can dispatch it to a thread pool in your callback.
h1. Topics and messages
While Stasis allows for the proliferation of many, many message types, we feel that creating too many message types would complicate the overall API. We have a small number of first class objects, (channel snapshots, bridge snapshots, etc.). If a message needs a first class object plus a small piece of additional data, {{blob}} objects are provided which attach a [JSON object|http://doxygen.asterisk.org/trunk/d4/d05/json_8h.html] to the first class object.
The details of topics and messages are documented [on doxygen.asterisk.org|http://doxygen.asterisk.org/trunk/df/deb/group__StasisTopicsAndMessages.html]. Some of the more important items to be aware of:
h2. First Class Message Object
h3. {{ast_channel_snapshot}}
A snapshot of the primary state of a channel, created by {{ast_channel_snapshot_create()}}.
h2. Second Class Message Objects
h3. {{ast_channel_blob}}
Often times, you find that you want to attach a piece of data to a snapshot for your message. For these cases, there's {{ast_channel_blob}}, which associated a channel snapshot with a JSON object (which is required to have a {{type}} field identifying it).
These are used to publish messages such as hangup requests, channel variable set events, etc.
h2. Channel Topics
h2. {{ast_channel_topic(chan)}}
This is the topic to which channel associated messages are published, including [channel snapshots|#ast_channel_snaphshot].
h2. {{ast_channel_topic_all()}}
This is an aggregation topic, to which all messages published to individual channel topics are forwarded.
h2. {{ast_channel_topic_all_cached()}}
This is a caching topic wrapping {{ast_channel_topic_all()}}, which caches {{ast_channel_snaphshot}} messages.
h1. Sample Code
h2. Publishing messages
{code:c|title=foo.h}
#include "asterisk/stasis.h"
/*! \brief Some structure containing the content of your message. */
struct ast_foo {
/* stuffz */
};
/*! \brief Message type for \ref ast_foo */
struct stasis_message_type *ast_foo_type(void);
/*!
* \brief Topic for the foo module.
*/
struct stasis_topic *ast_foo_topic(void);
{code}
{code:c|title=foo.c}
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/stasis.h"
#include "foo.h"
static struct stasis_message_type *foo_type;
struct stasis_topic *foo_topic;
struct stasis_message_type *ast_foo_type(void)
{
return foo_type;
}
struct stasis_topic *ast_foo_topic(void)
{
return foo_topic;
}
/*!
* \brief Convenience function to publish an \ref ast_foo message to the
* \ref foo_topic.
*/
static void publish_foo(struct ast_foo *foo)
{
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
msg = stasis_message_create(foo_type, foo);
if (!msg) {
return;
}
stasis_publish(foo_topic, msg);
}
/*
* Imagine lots of cool foo-related code here, which uses the above
* publish_foo message. Other foo-related messages may also be published
* to the foo_topic.
*/
static int unload_module(void)
{
ao2_cleanup(foo_type);
foo_type = NULL;
ao2_cleanup(foo_topic);
foo_topic = NULL;
return 0;
}
static int load_module(void)
{
foo_type = stasis_message_type_create("ast_foo");
if (!foo_type) {
return AST_MODULE_LOAD_FAILURE;
}
foo_topic = stasis_topic_create("foo");
if (!foo_topic) {
return AST_MODULE_LOAD_FAILURE;
}
return AST_MODULE_LOAD_SUCCESS;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "The wonders of foo",
.load = load_module,
.unload = unload_module
);
{code}
h2. Subscribing (no message router)
{code:c|title=bar.c}
#include "asterisk/astobj2.h"
#include "asterisk/stasis.h"
#include "foo.h"
struct ast_bar {
struct stasis_subscription *sub;
};
static void bar_dtor(void *obj)
{
struct ast_bar *bar = obj;
/* Since the subscription holds a reference, unsubscribe
* should happen before destruction.
*/
ast_assert(bar->sub == NULL);
}
static void bar_callback(void *data,
struct stasis_subscription *sub,
struct stasis_topic *topic,
struct stasis_message *message)
{
struct ast_bar *bar = data;
if (stasis_subscription_final_message(sub, message)) {
/* Final message; we can clean ourselves up */
ao2_cleanup(bar);
return;
}
if (ast_foo_type() == stasis_message_type(message)) {
struct ast_foo *foo = stasis_message_data(message);
/* A fooing we will go... */
} else if (ast_whatever_type() == stasis_message_type(message)) {
struct ast_whatever *whatever = stasis_message_data (message);
/* whatever */
}
}
struct ast_bar *ast_bar_create(void)
{
RAII_VAR(struct ast_bar *, bar, NULL, ao2_cleanup);
bar = ao2_alloc(sizeof(*bar), bar_dtor);
if (!bar) {
return NULL;
}
bar->sub = stasis_subscribe(ast_foo_topic(), bar_callback, bar);
if (!bar->sub) {
return NULL;
}
ao2_ref(bar, +1); /* The subscription hold a ref to bar */
ao2_ref(bar, +1); /* And we're returning a ref to bar */
return bar;
}
void ast_bar_shutdown(struct ast_bar *bar)
{
if (!bar) {
return NULL;
}
stasis_unsubscribe(bar->sub);
bar->sub = NULL;
}
{code}
h2. Subscribing (with message router)
{code:c|title=bar2.c}
#include "asterisk/astobj2.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_message_router.h"
#include "foo.h"
struct ast_bar {
struct stasis_message_router *router;
};
static void bar_dtor(void *obj)
{
struct ast_bar *bar = obj;
/* Since the subscription holds a reference, unsubscribe
* should happen before destruction.
*/
ast_assert(bar->router == NULL);
}
static void bar_default(void *data,
struct stasis_subscription *sub,
struct stasis_topic *topic,
struct stasis_message *message)
{
struct ast_bar *bar = data;
if (stasis_subscription_final_message(sub, message)) {
/* Final message; we can clean ourselves up */
ao2_cleanup(bar);
}
}
static void bar_foo(void *data,
struct stasis_subscription *sub,
struct stasis_topic *topic,
struct stasis_message *message)
{
struct ast_bar *bar = data;
struct ast_foo *foo;
ast_assert(ast_foo_type() == stasis_message_type(message));
foo = stasis_message_data(message);
/* A fooing we will go... */
}
static void bar_whatever(void *data,
struct stasis_subscription *sub,
struct stasis_topic *topic,
struct stasis_message *message)
{
struct ast_bar *bar = data;
struct ast_whatever *whatever;
ast_assert(ast_whatever_type() == stasis_message_type(message));
whatever = stasis_message_data (message);
/* whatever */
}
struct ast_bar *ast_bar_create(void)
{
RAII_VAR(struct ast_bar *, bar, NULL, ao2_cleanup);
int r;
bar = ao2_alloc(sizeof(*bar), bar_dtor);
if (!bar) {
return NULL;
}
bar->router = stasis_message_router_create(ast_foo_topic());
if (!bar->router) {
return NULL;
}
r = stasis_message_router_set_default(bar->router, bar_default, bar);
if (r != 0) {
ast_bar_shutdown(bar);
return NULL;
}
ao2_ref(bar, +1); /* The subscription hold a ref to bar */
r |= stasis_message_router_add(
bar->router, ast_foo_type(), bar_foo, bar);
r |= stasis_message_router_add(
bar->router, ast_whatever_type(), bar_whatever, bar);
if (r != 0) {
ast_bar_shutdown(bar);
return NULL;
}
ao2_ref(bar, +1);
return bar;
}
void ast_bar_shutdown(struct ast_bar *bar)
{
if (!bar) {
return;
}
stasis_message_router_unsubscribe(bar->router);
bar->router = NULL;
}
{code}
{numberedheadings}</span>
</pre> </td>
</tr>
</tbody>
</table> <p style="margin: 10px 0 0 0"></p> </td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td class="email-content-main mobile-expand action-padding last-row-padding" style="padding: 0px; border-collapse: collapse; border-left: 1px solid #ccc; border-right: 1px solid #ccc; border-top: 0; border-bottom: 0; padding: 0 15px 15px 16px; background-color: #fff; padding-bottom: 10px; padding-bottom: 10px">
<table id="actions-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 1px">
<tbody>
<tr>
<td id="actions-pattern-container" valign="middle" style="padding: 0px; border-collapse: collapse; padding: 15px 0 0 24px; vertical-align: middle">
<table align="left" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td class="actions-pattern-action-icon-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 0px; vertical-align: middle"><a href="https://wiki.asterisk.org/wiki/display/AST/Stasis+Message+Bus?src=email" title="View page Icon" style="color: #3b73af; text-decoration: none"><img class="actions-pattern-action-icon-image" height="16" width="16" border="0" title="View page Icon" src="cid:com.atlassian.confluence.plugins.confluence-email-resources%3Aview-page-email-adg-footer-item%3Aicon" alt="View page Icon" style="vertical-align: middle" /></a></td>
<td class="actions-pattern-action-text-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; padding-left: 5px; white-space: nowrap"><a href="https://wiki.asterisk.org/wiki/display/AST/Stasis+Message+Bus?src=email" title="View page" style="color: #3b73af; text-decoration: none">View page</a></td>
<td class="actions-pattern-action-bull" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; color: #999; padding: 0 5px">•</td>
</tr>
</tbody>
</table>
<table align="left" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td class="actions-pattern-action-icon-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 0px; vertical-align: middle"><a href="https://wiki.asterisk.org/wiki/display/AST/Stasis+Message+Bus?showComments=true&showCommentArea=true&src=email#addcomment" title="Add comment Icon" style="color: #3b73af; text-decoration: none"><img class="actions-pattern-action-icon-image" height="16" width="16" border="0" title="Add comment Icon" src="cid:com.atlassian.confluence.plugins.confluence-email-resources%3Aadd-comment-to-content-email-adg-footer-item%3Aicon" alt="Add comment Icon" style="vertical-align: middle" /></a></td>
<td class="actions-pattern-action-text-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; padding-left: 5px; white-space: nowrap"><a href="https://wiki.asterisk.org/wiki/display/AST/Stasis+Message+Bus?showComments=true&showCommentArea=true&src=email#addcomment" title="Add comment" style="color: #3b73af; text-decoration: none">Add comment</a></td>
<td class="actions-pattern-action-bull" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; color: #999; padding: 0 5px">•</td>
</tr>
</tbody>
</table>
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td class="actions-pattern-action-icon-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 0px; vertical-align: middle"><a href="https://wiki.asterisk.org/wiki/plugins/likes/like.action?contentId=22086002&src=email" title="Like Icon" style="color: #3b73af; text-decoration: none"><img class="actions-pattern-action-icon-image" height="16" width="16" border="0" title="Like Icon" src="cid:com.atlassian.confluence.plugins.confluence-like%3Aview-email-adg-content-item%3Aicon" alt="Like Icon" style="vertical-align: middle" /></a></td>
<td class="actions-pattern-action-text-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; padding-left: 5px; white-space: nowrap"><a href="https://wiki.asterisk.org/wiki/plugins/likes/like.action?contentId=22086002&src=email" title="Like" style="color: #3b73af; text-decoration: none">Like</a></td>
</tr>
</tbody>
</table> </td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td class="email-content-rounded-bottom mobile-expand" style="padding: 0px; border-collapse: collapse; color: #fff; height: 5px; line-height: 5px; padding: 0 15px 0 16px; background-color: #fff; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; border-top: 0; border-left: 1px solid #ccc; border-bottom: 1px solid #ccc; border-right: 1px solid #ccc; mso-line-height-rule: exactly"> </td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td id="footer-pattern" style="padding: 0px; border-collapse: collapse; padding: 12px 20px">
<table id="footer-pattern-container" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333">
<tbody>
<tr>
<td id="footer-pattern-links-container" width="100%" style="padding: 0px; border-collapse: collapse; color: #999; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px">
<table align="left" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px">
<tbody>
<tr>
<td class="footer-pattern-links mobile-resize-text" style="padding: 0px; border-collapse: collapse"><a href="https://wiki.asterisk.org/wiki/users/removespacenotification.action?spaceKey=AST&src=email" title="" style="color: #3b73af; text-decoration: none">Stop watching space</a></td>
<td class="footer-pattern-links-bull" style="padding: 0px; border-collapse: collapse; padding: 0 5px; color: #999">•</td>
</tr>
</tbody>
</table>
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px">
<tbody>
<tr>
<td class="footer-pattern-links mobile-resize-text" style="padding: 0px; border-collapse: collapse"><a href="https://wiki.asterisk.org/wiki/users/editmyemailsettings.action?src=email" title="" style="color: #3b73af; text-decoration: none">Manage notifications</a></td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td id="footer-pattern-text" class="mobile-resize-text" width="100%" style="padding: 0px; border-collapse: collapse; color: #999; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px; display: none">This message was sent by Atlassian Confluence 5.6.6</td>
</tr>
</tbody>
</table> </td>
</tr>
</tbody>
</table>
<table id="sealed-section" border="0" cellpadding="0" cellspacing="0" width="0" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; display: none">
<tbody>
<tr>
<td style="padding: 0px; border-collapse: collapse; border: 0; font-size: 0px; line-height: 0; mso-line-height-rule: exactly"></td>
</tr>
</tbody>
</table>
</body>
</html>