text:
package ovn

import (
	"fmt"
	"strings"
	"time"

	util "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"
	"github.com/sirupsen/logrus"
	kapi "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/wait"
)

func (oc *Controller) syncPods(pods []interface{}) {
	// get the list of logical switch ports (equivalent to pods)
	expectedLogicalPorts := make(map[string]bool)
	for _, podInterface := range pods {
		pod, ok := podInterface.(*kapi.Pod)
		if !ok {
			logrus.Errorf("Spurious object in syncPods: %v", podInterface)
			continue
		}
		logicalPort := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
		expectedLogicalPorts[logicalPort] = true
	}

	// get the list of logical ports from OVN
	output, stderr, err := util.RunOVNNbctl("--data=bare", "--no-heading",
		"--columns=name", "find", "logical_switch_port", "external_ids:pod=true")
	if err != nil {
		logrus.Errorf("Error in obtaining list of logical ports, "+
			"stderr: %q, err: %v",
			stderr, err)
		return
	}
	existingLogicalPorts := strings.Fields(output)
	for _, existingPort := range existingLogicalPorts {
		if _, ok := expectedLogicalPorts[existingPort]; !ok {
			// not found, delete this logical port
			logrus.Infof("Stale logical port found: %s. This logical port will be deleted.", existingPort)
			out, stderr, err := util.RunOVNNbctl("--if-exists", "lsp-del",
				existingPort)
			if err != nil {
				logrus.Errorf("Error in deleting pod's logical port "+
					"stdout: %q, stderr: %q err: %v",
					out, stderr, err)
			}
			if !oc.portGroupSupport {
				oc.deletePodAcls(existingPort)
			}
		}
	}
}

func (oc *Controller) deletePodAcls(logicalPort string) {
	// delete the ACL rules on OVN that corresponding pod has been deleted
	uuids, stderr, err := util.RunOVNNbctl("--data=bare", "--no-heading",
		"--columns=_uuid", "find", "ACL",
		fmt.Sprintf("external_ids:logical_port=%s", logicalPort))
	if err != nil {
		logrus.Errorf("Error in getting list of acls "+
			"stdout: %q, stderr: %q, error: %v", uuids, stderr, err)
		return
	}

	if uuids == "" {
		logrus.Debugf("deletePodAcls: returning because find " +
			"returned no ACLs")
		return
	}

	uuidSlice := strings.Fields(uuids)
	for _, uuid := range uuidSlice {
		// Get logical switch
		out, stderr, err := util.RunOVNNbctl("--data=bare",
			"--no-heading", "--columns=_uuid", "find", "logical_switch",
			fmt.Sprintf("acls{>=}%s", uuid))
		if err != nil {
			logrus.Errorf("find failed to get the logical_switch of acl "+
				"uuid=%s, stderr: %q, (%v)", uuid, stderr, err)
			continue
		}

		if out == "" {
			continue
		}
		logicalSwitch := out

		_, stderr, err = util.RunOVNNbctl("--if-exists", "remove",
			"logical_switch", logicalSwitch, "acls", uuid)
		if err != nil {
			logrus.Errorf("failed to delete the allow-from rule %s for"+
				" logical_switch=%s, logical_port=%s, stderr: %q, (%v)",
				uuid, logicalSwitch, logicalPort, stderr, err)
			continue
		}
	}
}

func (oc *Controller) getLogicalPortUUID(logicalPort string) string {
	if oc.logicalPortUUIDCache[logicalPort] != "" {
		return oc.logicalPortUUIDCache[logicalPort]
	}

	out, stderr, err := util.RunOVNNbctl("--if-exists", "get",
		"logical_switch_port", logicalPort, "_uuid")
	if err != nil {
		logrus.Errorf("Error while getting uuid for logical_switch_port "+
			"%s, stderr: %q, err: %v", logicalPort, stderr, err)
		return ""
	}

	if out == "" {
		return out
	}

	oc.logicalPortUUIDCache[logicalPort] = out
	return oc.logicalPortUUIDCache[logicalPort]
}

func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string, error) {
	var gatewayIPMaskStr, stderr string
	var ok bool
	var err error

	oc.lsMutex.Lock()
	defer oc.lsMutex.Unlock()
	if gatewayIPMaskStr, ok = oc.gatewayCache[logicalSwitch]; !ok {
		gatewayIPMaskStr, stderr, err = util.RunOVNNbctl("--if-exists",
			"get", "logical_switch", logicalSwitch,
			"external_ids:gateway_ip")
		if err != nil {
			logrus.Errorf("Failed to get gateway IP:  %s, stderr: %q, %v",
				gatewayIPMaskStr, stderr, err)
			return "", "", err
		}
		if gatewayIPMaskStr == "" {
			return "", "", fmt.Errorf("Empty gateway IP in logical switch %s",
				logicalSwitch)
		}
		oc.gatewayCache[logicalSwitch] = gatewayIPMaskStr
	}
	gatewayIPMask := strings.Split(gatewayIPMaskStr, "/")
	gatewayIP := gatewayIPMask[0]
	mask := gatewayIPMask[1]
	logrus.Debugf("Gateway IP: %s, Mask: %s", gatewayIP, mask)
	return gatewayIP, mask, nil
}

func (oc *Controller) deleteLogicalPort(pod *kapi.Pod) {
	if pod.Spec.HostNetwork {
		return
	}

	logrus.Infof("Deleting pod: %s", pod.Name)
	logicalPort := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	out, stderr, err := util.RunOVNNbctl("--if-exists", "lsp-del",
		logicalPort)
	if err != nil {
		logrus.Errorf("Error in deleting pod logical port "+
			"stdout: %q, stderr: %q, (%v)",
			out, stderr, err)
	}

	ipAddress := oc.getIPFromOvnAnnotation(pod.Annotations["ovn"])

	delete(oc.logicalPortCache, logicalPort)

	oc.lspMutex.Lock()
	delete(oc.lspIngressDenyCache, logicalPort)
	delete(oc.lspEgressDenyCache, logicalPort)
	delete(oc.logicalPortUUIDCache, logicalPort)
	oc.lspMutex.Unlock()

	if !oc.portGroupSupport {
		oc.deleteACLDenyOld(pod.Namespace, pod.Spec.NodeName, logicalPort,
			"Ingress")
		oc.deleteACLDenyOld(pod.Namespace, pod.Spec.NodeName, logicalPort,
			"Egress")
	}
	oc.deletePodFromNamespaceAddressSet(pod.Namespace, ipAddress)
	return
}

func (oc *Controller) waitForNodeLogicalSwitch(nodeName string) error {
	oc.lsMutex.Lock()
	ok := oc.logicalSwitchCache[nodeName]
	oc.lsMutex.Unlock()
	// Fast return if we already have the node switch in our cache
	if ok {
		return nil
	}

	// Otherwise wait for the node logical switch to be created by the ClusterController.
	// The node switch will be created very soon after startup so we should
	// only be waiting here once per node at most.
	if err := wait.PollImmediate(500*time.Millisecond, 30*time.Second, func() (bool, error) {
		if _, _, err := util.RunOVNNbctl("get", "logical_switch", nodeName, "other-config"); err != nil {
			return false, nil
		}
		return true, nil
	}); err != nil {
		logrus.Errorf("timed out waiting for node %q logical switch: %v", nodeName, err)
		return err
	}

	oc.lsMutex.Lock()
	defer oc.lsMutex.Unlock()
	if !oc.logicalSwitchCache[nodeName] {
		if err := oc.addAllowACLFromNode(nodeName); err != nil {
			return err
		}
		oc.logicalSwitchCache[nodeName] = true
	}
	return nil
}

func (oc *Controller) addLogicalPort(pod *kapi.Pod) {
	var out, stderr string
	var err error
	if pod.Spec.HostNetwork {
		return
	}

	logicalSwitch := pod.Spec.NodeName
	if logicalSwitch == "" {
		logrus.Errorf("Failed to find the logical switch for pod %s/%s",
			pod.Namespace, pod.Name)
		return
	}

	if err = oc.waitForNodeLogicalSwitch(pod.Spec.NodeName); err != nil {
		return
	}

	portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	logrus.Debugf("Creating logical port for %s on switch %s", portName, logicalSwitch)

	annotation, isStaticIP := pod.Annotations["ovn"]

	// If pod already has annotations, just add the lsp with static ip/mac.
	// Else, create the lsp with dynamic addresses.
	if isStaticIP {
		ipAddress := oc.getIPFromOvnAnnotation(annotation)
		macAddress := oc.getMacFromOvnAnnotation(annotation)

		out, stderr, err = util.RunOVNNbctl("--may-exist", "lsp-add",
			logicalSwitch, portName, "--", "lsp-set-addresses", portName,
			fmt.Sprintf("%s %s", macAddress, ipAddress), "--", "set",
			"logical_switch_port", portName,
			"external-ids:namespace="+pod.Namespace,
			"external-ids:logical_switch="+logicalSwitch,
			"external-ids:pod=true", "--", "--if-exists",
			"clear", "logical_switch_port", portName, "dynamic_addresses")
		if err != nil {
			logrus.Errorf("Failed to add logical port to switch "+
				"stdout: %q, stderr: %q (%v)",
				out, stderr, err)
			return
		}
	} else {
		out, stderr, err = util.RunOVNNbctl("--wait=sb", "--",
			"--may-exist", "lsp-add", logicalSwitch, portName,
			"--", "lsp-set-addresses",
			portName, "dynamic", "--", "set",
			"logical_switch_port", portName,
			"external-ids:namespace="+pod.Namespace,
			"external-ids:logical_switch="+logicalSwitch,
			"external-ids:pod=true")
		if err != nil {
			logrus.Errorf("Error while creating logical port %s "+
				"stdout: %q, stderr: %q (%v)",
				portName, out, stderr, err)
			return
		}
	}

	oc.logicalPortCache[portName] = logicalSwitch

	gatewayIP, mask, err := oc.getGatewayFromSwitch(logicalSwitch)
	if err != nil {
		logrus.Errorf("Error obtaining gateway address for switch %s", logicalSwitch)
		return
	}

	count := 30
	for count > 0 {
		if isStaticIP {
			out, stderr, err = util.RunOVNNbctl("get",
				"logical_switch_port", portName, "addresses")
		} else {
			out, stderr, err = util.RunOVNNbctl("get",
				"logical_switch_port", portName, "dynamic_addresses")
		}
		if err == nil && out != "[]" {
			break
		}
		if err != nil {
			logrus.Errorf("Error while obtaining addresses for %s - %v", portName,
				err)
			return
		}
		time.Sleep(time.Second)
		count--
	}
	if count == 0 {
		logrus.Errorf("Error while obtaining addresses for %s "+
			"stdout: %q, stderr: %q, (%v)", portName, out, stderr, err)
		return
	}

	// static addresses have format ["0a:00:00:00:00:01 192.168.1.3"], while
	// dynamic addresses have format "0a:00:00:00:00:01 192.168.1.3".
	outStr := strings.TrimLeft(out, `[`)
	outStr = strings.TrimRight(outStr, `]`)
	outStr = strings.Trim(outStr, `"`)
	addresses := strings.Split(outStr, " ")
	if len(addresses) != 2 {
		logrus.Errorf("Error while obtaining addresses for %s", portName)
		return
	}

	if !isStaticIP {
		annotation = fmt.Sprintf(`{\"ip_address\":\"%s/%s\", \"mac_address\":\"%s\", \"gateway_ip\": \"%s\"}`, addresses[1], mask, addresses[0], gatewayIP)
		logrus.Debugf("Annotation values: ip=%s/%s ; mac=%s ; gw=%s\nAnnotation=%s", addresses[1], mask, addresses[0], gatewayIP, annotation)
		err = oc.kube.SetAnnotationOnPod(pod, "ovn", annotation)
		if err != nil {
			logrus.Errorf("Failed to set annotation on pod %s - %v", pod.Name, err)
		}
	}
	oc.addPodToNamespaceAddressSet(pod.Namespace, addresses[1])

	return
}

// AddLogicalPortWithIP add logical port with static ip address
// and mac adddress for the pod
func (oc *Controller) AddLogicalPortWithIP(pod *kapi.Pod) {
	if pod.Spec.HostNetwork {
		return
	}

	portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	logicalSwitch := pod.Spec.NodeName
	logrus.Debugf("Creating logical port for %s on switch %s", portName,
		logicalSwitch)

	annotation, ok := pod.Annotations["ovn"]
	if !ok {
		logrus.Errorf("Failed to get ovn annotation from pod!")
		return
	}
	ipAddress := oc.getIPFromOvnAnnotation(annotation)
	macAddress := oc.getMacFromOvnAnnotation(annotation)

	stdout, stderr, err := util.RunOVNNbctl("--", "--may-exist", "lsp-add",
		logicalSwitch, portName, "--", "lsp-set-addresses", portName,
		fmt.Sprintf("%s %s", macAddress, ipAddress))
	if err != nil {
		logrus.Errorf("Failed to add logical port to switch, stdout: %q, "+
			"stderr: %q, error: %v", stdout, stderr, err)
		return
	}
}


text:
import { toastr as toastrEmitter } from 'react-redux-toastr';
import options from './options';

export default ({ icon, title, message, extra, ...otherOptions }) => {
  toastrEmitter.success(title, message, {
    icon,
    ...options,
    ...otherOptions,
    component: extra,
  });
};

redpajama_set_name: RedPajamaGithub


text:
.. _solfec-1.0-theory-locdyn:

Local dynamics
==============

Let us start by restating the constrained time stepping
scheme from the :ref:`previous section <timestepping1>`

.. math::
  :label: q1

  \mathbf{q}^{t+\frac{h}{2}}=\mathbf{q}^{t}+\frac{h}{2}\mathbf{u}^{t}

.. math::
  :label: u2

  \mathbf{u}^{t+h}=\mathbf{u}^{t}+\mathbf{A}^{-1}h\mathbf{f}\left(\mathbf{q}^{t+\frac{h}{2}},\mathbf{u}^{t}\right)+
  \mathbf{A}^{-1}h\mathbf{H}^{T}\left(\mathbf{q}^{t+\frac{h}{2}}\right)\mathbf{R}

.. math::
  :label: UHu2

  \mathbf{U}=\mathbf{H}\left(\mathbf{q}^{t+\frac{h}{2}}\right)\mathbf{u}

.. math::
  :label: CUR2

  \mathbf{C}\left(\mathbf{U},\mathbf{R}\right)=\mathbf{0}

.. math::
  :label: q2

  \mathbf{q}^{t+h}=\mathbf{q}^{t+\frac{h}{2}}+\frac{h}{2}\mathbf{u}^{t+h}

We said, that the equations :eq:`u2`, :eq:`UHu2`, :eq:`CUR2`
are solved together, implicitly. In practice, since a solution process
may take many iterations, it is often efficient to produce an
assembled form of the relationship between :math:`\mathbf{U}` and :math:`\mathbf{R}`,
and use it together with :math:`\mathbf{C}\left(\mathbf{U},\mathbf{R}\right)`,
to find reaction forces :math:`\mathbf{R}`. By substituting :eq:`u2`
into :eq:`UHu2` we obtain

.. math::

  \mathbf{U}=\mathbf{H}\left(\mathbf{u}^{t}+\mathbf{A}^{-1}h\mathbf{f}\right)+\mathbf{H}\mathbf{A}^{-1}h\mathbf{H}^{T}\mathbf{R}

and rewrite it as

.. math::
  :label: UBWR

  \mathbf{U}=\mathbf{B}+\mathbf{W}\mathbf{R}

where

.. math::
  :label: B0

  \mathbf{B}=\mathbf{H}\left(\mathbf{u}^{t}+\mathbf{A}^{-1}h\mathbf{f}\right)

.. math::
  :label: W0

  \mathbf{W}=h\mathbf{H}\mathbf{A}^{-1}\mathbf{H}^{T}\label{eq:W0}

Relation :eq:`UBWR` can be called *local dynamics*, since
it relates point forces and (relative) point velocities. :math:`\mathbf{B}`
can be called local free velocity, since it is a relative local velocity
of constraints when no reaction forces are applied. :math:`\mathbf{W}`
can be called a generalized inverse inertia matrix.

.. _detailed_notation:

Detailed multi--body notation
-----------------------------

So far we have presented formulas at certain level of generality.
Let us now present detailed multi--body formulas. Let :math:`\left\{ \mathcal{B}_{i}\right\}`
be a set of bodies and :math:`\left\{ \mathcal{C}_{\alpha}\right\}` be
a set of local frames. To each local frame :math:`\mathcal{C}_{\alpha}`
there corresponds a pair of bodies :math:`\mathcal{B}_{i}` and :math:`\mathcal{B}_{j}`.
Let :math:`\mathcal{B}_{j}` be the body, to which the local frame is attached.
:math:`\mathcal{B}_{j}` will be called the *master* in :math:`\mathcal{C}_{\alpha}`
and denoted by :math:`\mathcal{M}_{\alpha}`. Consequently, :math:`\mathcal{B}_{i}`
will be called the *slave* in :math:`\mathcal{C}_{\alpha}` and denoted
by :math:`\mathcal{S}_{\alpha}`. Of course, the choice is arbitrary. Considering
evolution of a multi--body system over an interval :math:`\left[t,t+h\right]`,
an analogue of equation :eq:`UBWR` can be written down for each of the local frames

.. math::
  :label: dynloc

  \mathbf{U_{\alpha}}=\mathbf{B_{\alpha}}+\sum_{\beta}\mathbf{W}_{\alpha\beta}\mathbf{R}_{\beta}

where

.. math::
  :label: U

  \mathbf{U}_{\alpha}=\mathbf{H}_{i\alpha}\mathbf{u}_{i}^{t+h}-\mathbf{H}_{j\alpha}\mathbf{u}_{j}^{t+h}

.. math::
  :label: Bal

  \mathbf{B}_{\alpha}=\mathbf{H}_{i\alpha}\left(\mathbf{u}_{i}^{t}+\mathbf{A}_{i}^{-1}h\mathbf{f}_{i}\right)-
  \mathbf{H}_{j\alpha}\left(\mathbf{u}_{j}^{t}+\mathbf{A}_{j}^{-1}h\mathbf{f}_{j}\right)

.. math::
  :label: Walbe

  \left.\mathbf{W}_{\alpha\beta}\right|_{\alpha\ne\beta}=s_{\alpha\beta}h\mathbf{H}_{k_{\beta}\alpha}\mathbf{A}_{k_{\beta}}^{-1}\mathbf{H}_{k_{\beta}\beta}^{T}

.. math::
  :label: Walal

  \mathbf{W}_{\alpha\alpha}=h\mathbf{H}_{i\alpha}\mathbf{A}_{i}^{-1}\mathbf{H}_{i\alpha}^{T}+h\mathbf{H}_{j\alpha}\mathbf{A}_{j}^{-1}\mathbf{H}_{j\alpha}^{T}

.. math::
  k_{\beta}=\left\{ \begin{array}{cc}
  i & \textrm{if }\mathcal{B}_{i}\in\mathcal{C}_{\beta}\\
  j & \textrm{if }\mathcal{B}_{j}\in\mathbf{\mathcal{C}_{\beta}}
  \end{array}\right.

.. math::
  :label: sdef

  s_{\alpha\beta}=\left\{ \begin{array}{rl}
  -1 & \textrm{if }\mathcal{B}_{k_{\beta}}\textrm{ is }\left(\mathcal{M}_{\alpha}\wedge\mathcal{S}_{\beta}\right)\vee\left(\mathcal{S}_{\alpha}\wedge\mathcal{M}_{\beta}\right)\\
  1 & \textrm{otherwise}
  \end{array}\right.

The above formulae can be conveniently applied in a computer implementation.
They stem from the following, juxtaposed algebra of multi--body dynamics.
Let :math:`\mathbf{q}`, :math:`\mathbf{u}`, :math:`\mathbf{f}`, :math:`\mathbf{A}`
gather the suitable vectors and matrices as

.. math::
  :label: qufM

  \mathbf{q}=\left[\begin{array}{c}
  \mathbf{q}_{1}\\
  \mathbf{q}_{2}\\
  ...\\
  \mathbf{q}_{n}
  \end{array}\right],\mathbf{u}=\left[\begin{array}{c}
  \mathbf{u}_{1}\\
  \mathbf{u}_{2}\\
  ...\\
  \mathbf{u}_{n}
  \end{array}\right],\mathbf{f}=\left[\begin{array}{c}
  \mathbf{f}_{1}\\
  \mathbf{f}_{2}\\
  ...\\
  \mathbf{f}_{n}
  \end{array}\right],\mathbf{A}=\left[\begin{array}{cccc}
  \mathbf{A}_{1}\\
   & \mathbf{A}_{2}\\
    &  & ...\\
     &  &  & \mathbf{A}_{n}
     \end{array}\right]

To each local frame :math:`\mathcal{C}_{\alpha}`, there corresponds a block--row
of the global :math:`\mathbf{H}` operator

.. math::
  :label: Hglob

  \mathbf{H}=\left[\begin{array}{ccccccc}
  ... & -\mathbf{H}_{j1} & ... & \mathbf{H}_{i1} & ...\\
  ... & ... & ... & ... & ... & ... & ...\\
  & ... & \mathbf{H}_{i\alpha} & ... & -\mathbf{H}_{j\alpha} & ...\\
  ... & ... & ... & ... & ... & ... & ...\\
   &  & ... & \mathbf{H}_{im} & ... & -\mathbf{H}_{jm} & ...
   \end{array}\right]

where

.. math::

  \mathbf{H}_{k\alpha}=\mathbf{H}\left(\left\{ \mathbf{a}^{i}\right\} \in\mathcal{C}_{\alpha},\mathbf{X}\in\mathcal{B}_{k}\right)

is evaluated according to one of the specific formulas :ref:`introduced in the section on constraints <solfec-1.0-theory-constraints>`.

.. _W_matrix:

The :math:`\mathbf{W}` matrix
-----------------------------

:math:`\mathbf{W}` maps local forces into local relative velocities.
Algebraically, it is represented by a sparse matrix, composed of dense
:math:`3\times3` blocks :math:`\mathbf{W}_{\alpha\beta}`. The sparsity pattern
of :math:`\textbf{ $\mathbf{W}$}` corresponds to the vertex connectivity in
the graph of local frames. Vertices of this graph are the local frames
:math:`\left\{ \mathcal{C}_{\alpha}\right\}`, while the edges comprise
a subset of all bodies :math:`\left\{ \mathcal{B}_{i}\right\}`, such that
:math:`\mathcal{B}_{i}\in\mathcal{C_{\alpha}}` and :math:`\mathcal{B}_{i}\in\mathcal{C}_{\beta}`
for :math:`\alpha\ne\beta`. This has been illustrated in :numref:`locgraph`.
Operator :math:`\mathbf{W}` derives from the formula

.. math::

  \mathbf{W}=\mathbf{H}\mathbf{A}^{-1}\mathbf{H}^{T}

where :math:`\mathbf{A}` is a :math:`n\times n` symmetric and positive definite
matrix, and :math:`\mathbf{H}` is an :math:`m\times n` transformation operator.
:math:`\mathbf{W}` is an :math:`m\times m` symmetric matrix. It is positive
definite, provided rows of :math:`\mathbf{H}` are linearly independent.
This is easiest to see from the flow of the actions in the above formula.
A local force :math:`\mathbf{R}` is first mapped by :math:`\mathbf{H}^{T}` into
a generalized force :math:`\mathbf{r}`. If rows of :math:`\mathbf{H}` are not
linearly independent, then there exist :math:`\mathbf{R}_{1}\ne\mathbf{R}_{2}`
such that :math:`\mathbf{H}^{T}\mathbf{R}_{1}=\mathbf{H}^{T}\mathbf{R}_{2}`
and hence :math:`\mathbf{W}` fails to be a bijection. This means, that
the null space of :math:`\mathbf{W}` is larger than :math:`\left\{ \mathbf{0}\right\}`,
so that :math:`\mathbf{W}` is not invertible in the usual sense. :math:`\mathbf{W}`
becomes singular whenever :math:`m>n`, which is trivially related to the
number of considered bodies relative to the number of constraints.
On the other hand, one can always introduce singularity of :math:`\mathbf{W}`
by using local frames between the same pair of bodies, in such a way
that their :math:`\mathbf{H}` operators are linearly dependent. This can
be related to deformability of kinematic models. For example, the
pseudo--rigid body has a linear distribution of the instantaneous velocity
over an arbitrary flat surface. Thus, the relative velocity between
two bodies over a flat surface is fully parametrized by three points.
A larger number of local frames results in the singularity of :math:`\mathbf{W}`.
So does their collinearity. In practice, :math:`\mathbf{W}` often becomes
numerically singular for many practically encountered configurations
of local frames. Indeterminacy of local forces :math:`\mathbf{R}` is then
an unavoidable consequence of either kinematic simplicity, or geometric
complexity, and as such it needs to be accepted in numerical practice.

.. _locgraph:

.. figure:: ../figures/locgraph.png
   :width: 60%
   :align: center

   A graph of local frames and the corresponding pattern of :math:`\mathbf{W}`.

Implementation
--------------

Local dynamics is implemented in files `ldy.h <https://github.com/tkoziara/solfec/blob/master/ldy.h>`_
and `ldy.c <https://github.com/tkoziara/solfec/blob/master/ldy.h>`_.

Off--diagonal blocks of :math:`\mathbf{W}_{\alpha\beta}` :eq:`Walal`,
diagonal block :math:`\mathbf{W}_{\alpha\alpha}` :eq:`Walal`,
and the entire :math:`\mathbf{U}=\mathbf{B}+\mathbf{W}\mathbf{R}` system :eq:`UBWR` are
declared in `ldy.h:39 <https://github.com/tkoziara/solfec/blob/master/ldy.h#L39>`_ as follows:

.. literalinclude:: ../../../solfec-1.0/ldy.h
   :lines: 39-41
   :lineno-start: 39
   :linenos:

Off--diagonal blocks of :math:`\mathbf{W}_{\alpha\beta}` :eq:`Walbe` are declared in
`ldy.h:44 <https://github.com/tkoziara/solfec/blob/master/ldy.h#L44>`_ as follows:

.. code-block:: c
  :lineno-start: 44
  :linenos:

  struct offb
  {
    double W [9];
    ...
    DIAB *dia;
    OFFB *n;
  };

.. stop ** in vim

Diagonal blocks of :math:`\mathbf{W}_{\alpha\alpha}` :eq:`Walal` and
free velocity :math:`\mathbf{B}_{\alpha}` :eq:`Bal` are declared in
`ldy.h:53 <https://github.com/tkoziara/solfec/blob/master/ldy.h#L53>`_ as follows:

.. code-block:: c
  :lineno-start: 53
  :linenos:

  struct diab
  {
    double *R, /* average reaction ... */

.. stop ** in vim

.. code-block:: c
  :lineno-start: 58
  :linenos:

           W [9], /* diagonal block of W */
	   ...
	   B [3], /* free velocity */

.. stop ** in vim

.. code-block:: c
  :lineno-start: 63
  :linenos:

    OFFB *adj;

    CON *con;  /* the underlying constraint ... */

.. stop ** in vim

.. code-block:: c
  :lineno-start: 71
  :linenos:

    DIAB *p, *n;

.. stop ** in vim

.. code-block:: c
  :lineno-start: 78
  :linenos:

  };

The local dynamics system is stored as a doubly linked list of diagonal blocs
further pointing to singly linked lists of off--diagonal blocks in
`ldy.h:81 <https://github.com/tkoziara/solfec/blob/master/ldy.h#L81>`_ as:

.. code-block:: c
  :lineno-start: 81
  :linenos:

  struct locdyn
  {

.. code-block:: c
  :lineno-start: 87
  :linenos:

  DIAB *dia; /* list of diagonal blocks */

.. stop ** in vim

.. code-block:: c
  :lineno-start: 90
  :linenos:

  };

.. |br| raw:: html

  <br />

Symbolic insertion of rows into :math:`\mathbf{W}`, without assembling of the numeric block values,
is administered by `ldy.c:LOCDYN_Insert <https://github.com/tkoziara/solfec/blob/master/ldy.c#L485>`_. |br|
Similarly, deletion of rows from :math:`\mathbf{W}` is administered by
`ldy.c:LOCDYN_Remove <https://github.com/tkoziara/solfec/blob/master/ldy.c#L564>`_. |br|
Assembling of :math:`\mathbf{W}` and :math:`\mathbf{B}` is invoked by `ldy.c:LOCDYN_Update_Begin <https://github.com/tkoziara/solfec/blob/master/ldy.c#L619>`_.


text:
/** Este path es reemplazado por la url absoluta del proyecto en S3
* NO-TOCAR
*/

// import { formatNumber } from './helpers';

window.PATH_APP = '';
/** NO-TOCAR-END */

window.onload = function () {
  /** resize app */
  let doit;
  window.onresize = function () {
    clearTimeout(doit);
    doit = setTimeout(() => { console.log('resize app'); }, 200);
  };
};

// pymChild = new pym.Child();
// pymChild.sendHeight();

/** FIX PROMISE CROSSBROWSER */
// // import Promise from 'promise-polyfill';

// // To add to window
// if (!window.Promise) {
//   window.Promise = Promise;
// }


text:
<?php

namespace Skytells\Support\Facades;

use Skytells\Support\Testing\Fakes\MailFake;

/**
 * @see \Skytells\Mail\Mailer
 */
class Mail extends Facade
{
    /**
     * Replace the bound instance with a fake.
     *
     * @return void
     */
    public static function fake()
    {
        static::swap(new MailFake);
    }

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'mailer';
    }
}


text:
from django.conf import settings
from django.contrib.auth.models import Permission

from social.pipeline.user import create_user as social_create_user

from pyhn.apps.account.models import Profile

def create_user(strategy, details, response, uid, user=None, *args, **kwargs):
    info = social_create_user(
        strategy, details, response, uid, user, *args, **kwargs
    )

    if info['is_new']:
        user = info['user']
        if settings.PYHN_NEW_USER_CAN_SUBMIT:
            permission = Permission.objects.get(codename='can_submit')
            user.user_permissions.add(permission)

        profile = Profile(user_ptr=user)
        profile.username = user.username
        profile.email = user.email
        profile.about = ''
        profile.save()

    return {'is_new': True, 'user': user}


text:
/*!
 * Start Bootstrap - Creative Bootstrap Theme (http://startbootstrap.com)
 * Code licensed under the Apache License v2.0.
 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 */

html,
body {
    width: 100%;
    height: 100%;
}

body {
    font-family: Merriweather,'Helvetica Neue',Arial,sans-serif;
}

hr {
    max-width: 50px;
    border-color: #f05f40;
    border-width: 3px;
}

hr.light {
    border-color: #fff;
}

a {
    color: #f05f40;
    -webkit-transition: all .35s;
    -moz-transition: all .35s;
    transition: all .35s;
}

a:hover,
a:focus {
    color: #eb3812;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
}
.wrapper {
  margin: 50px auto;
  width: 280px;
  height: 370px;
  background: white;
  border-radius: 10px;
  -webkit-box-shadow: 0px 0px 8px rgba(0,0,0,0.3);
  -moz-box-shadow:    0px 0px 8px rgba(0,0,0,0.3);
  box-shadow:         0px 0px 8px rgba(0,0,0,0.3);
  position: relative;
  z-index: 90;
}

.ribbon-wrapper-green {
  width: 85px;
  height: 88px;
  overflow: hidden;
  position: absolute;
  top: -3px;
  right: -3px;
}

.ribbon-green {
  font: bold 15px Sans-Serif;
  color: #333;
  text-align: center;
  text-shadow: rgba(255,255,255,0.5) 0px 1px 0px;
  -webkit-transform: rotate(45deg);
  -moz-transform:    rotate(45deg);
  -ms-transform:     rotate(45deg);
  -o-transform:      rotate(45deg);
  position: relative;
  padding: 7px 0;
  left: -5px;
  top: 15px;
  width: 120px;
  background-color: #BFDC7A;
  background-image: -webkit-gradient(linear, left top, left bottom, from(#BFDC7A), to(#8EBF45));
  background-image: -webkit-linear-gradient(top, #BFDC7A, #8EBF45);
  background-image:    -moz-linear-gradient(top, #BFDC7A, #8EBF45);
  background-image:     -ms-linear-gradient(top, #BFDC7A, #8EBF45);
  background-image:      -o-linear-gradient(top, #BFDC7A, #8EBF45);
  color: #6a6340;
  -webkit-box-shadow: 0px 0px 3px rgba(0,0,0,0.3);
  -moz-box-shadow:    0px 0px 3px rgba(0,0,0,0.3);
  box-shadow:         0px 0px 3px rgba(0,0,0,0.3);
}

.ribbon-green:before, .ribbon-green:after {
  content: "";
  border-top:   3px solid #6e8900;
  border-left:  3px solid transparent;
  border-right: 3px solid transparent;
  position:absolute;
  bottom: -3px;
}

.ribbon-green:before {
  left: 0;
}
.ribbon-green:after {
  right: 0;
}

p {
    margin-bottom: 20px;
    font-size: 16px;
    line-height: 1.5;
}

.bg-primary {
    background-color: #717171;
}
.bg-secondary {
    background-colour: #DDEAFC;
}

.bg-dark {
    color: #fff;
    background-color: #222;
}

.text-faded {
    color: rgba(255,255,255,.7);
}

section {
    padding: 100px 0;
}

aside {
    padding: 50px 0;
}

.no-padding {
    padding: 0;
}

.navbar-default {
    border-color: rgba(33,34,34,.05);
    font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
    background-color: #fff;
    -webkit-transition: all .35s;
    -moz-transition: all .35s;
    transition: all .35s;
}

.navbar-default .navbar-header .navbar-brand {
    text-transform: uppercase;
    font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
    font-weight: 700;
    color: #f05f40;
}

.navbar-default .navbar-header .navbar-brand:hover,
.navbar-default .navbar-header .navbar-brand:focus {
    color: #eb3812;
}

.navbar-default .nav > li>a,
.navbar-default .nav>li>a:focus {
    text-transform: uppercase;
    font-size: 13px;
    font-weight: 700;
    color: #222;
}

.navbar-default .nav > li>a:hover,
.navbar-default .nav>li>a:focus:hover {
    color: #f05f40;
}

.navbar-default .nav > li.active>a,
.navbar-default .nav>li.active>a:focus {
    color: #f05f40!important;
    background-color: transparent;
}

.navbar-default .nav > li.active>a:hover,
.navbar-default .nav>li.active>a:focus:hover {
    background-color: transparent;
}

@media(min-width:768px) {
    .navbar-default {
        border-color: rgba(255,255,255,.3);
        background-color: transparent;
    }

    .navbar-default .navbar-header .navbar-brand {
        color: rgba(255,255,255,.7);
    }

    .navbar-default .navbar-header .navbar-brand:hover,
    .navbar-default .navbar-header .navbar-brand:focus {
        color: #fff;
    }

    .navbar-default .nav > li>a,
    .navbar-default .nav>li>a:focus {
        color: rgba(255,255,255,1);
    }

    .navbar-default .nav > li>a:hover,
    .navbar-default .nav>li>a:focus:hover {
        color: #fff;
    }

    .navbar-default.affix {
        border-color: rgba(34,34,34,.05);
        background-color: #fff;
    }

    .navbar-default.affix .navbar-header .navbar-brand {
        font-size: 14px;
        color: #f05f40;
    }

    .navbar-default.affix .navbar-header .navbar-brand:hover,
    .navbar-default.affix .navbar-header .navbar-brand:focus {
        color: #eb3812;
    }

    .navbar-default.affix .nav > li>a,
    .navbar-default.affix .nav>li>a:focus {
        color: #222;
    }

    .navbar-default.affix .nav > li>a:hover,
    .navbar-default.affix .nav>li>a:focus:hover {
        color: #f05f40;
    }
}

header {
    position: relative;
    width: 100%;
    min-height: auto;
    text-align: center;
    color: #fFf;
    background-image: url(../img/header.jpg);
    background-position: center;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    background-size: cover;
    -o-background-size: cover;
}

header .header-content {
    position: relative;
    width: 100%;
    padding: 100px 15px;
    text-align: center;
}

header .header-content .header-content-inner h1 {
    margin-top: 0;
    margin-bottom: 0;
    text-transform: uppercase;
    font-weight: 700;
}

header .header-content .header-content-inner hr {
    margin: 30px auto;
}

header .header-content .header-content-inner p {
    margin-bottom: 50px;
    font-size: 16px;
    font-weight: 300;
    color: rgba(255,255,255,.7);
}

@media(min-width:768px) {
    header {
        min-height: 100%;
    }

    header .header-content {
        position: absolute;
        top: 50%;
        padding: 0 50px;
        -webkit-transform: translateY(-50%);
        -ms-transform: translateY(-50%);
        transform: translateY(-50%);
    }

    header .header-content .header-content-inner {
        margin-right: auto;
        margin-left: auto;
        max-width: 1000px;
    }

    header .header-content .header-content-inner p {
        margin-right: auto;
        margin-left: auto;
        max-width: 80%;
        font-size: 18px;
    }
}

.section-heading {
    margin-top: 0;
}

.service-box {
    margin: 50px auto 0;
    max-width: 400px;
}

@media(min-width:992px) {
    .service-box {
        margin: 20px auto 0;
    }
}

.service-box p {
    margin-bottom: 0;
}

.portfolio-box {
    display: block;
    position: relative;
    margin: 0 auto;
    max-width: 650px;
}

.portfolio-box .portfolio-box-caption {
    display: block;
    position: absolute;
    bottom: 0;
    width: 100%;
    height: 100%;
    text-align: center;
    color: #fff;
    opacity: 0;
    background: rgba(240,95,64,.9);
    -webkit-transition: all .35s;
    -moz-transition: all .35s;
    transition: all .35s;
}

.portfolio-box .portfolio-box-caption .portfolio-box-caption-content {
    position: absolute;
    top: 50%;
    width: 100%;
    text-align: center;
    transform: translateY(-50%);
}

.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category,
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name {
    padding: 0 15px;
    font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
}

.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category {
    text-transform: uppercase;
    font-size: 14px;
    font-weight: 600;
}

.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name {
    font-size: 18px;
}

.portfolio-box:hover .portfolio-box-caption {
    opacity: 1;
}

@media(min-width:768px) {
    .portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category {
        font-size: 16px;
    }

    .portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name {
        font-size: 22px;
    }
}

.call-to-action h2 {
    margin: 0 auto 20px;
}

.text-primary {
    color: #f05f40;
}

.no-gutter > [class*=col-] {
    padding-right: 0;
    padding-left: 0;
}

.btn-default {
    border-color: #fff;
    color: #222;
    background-color: #fff;
    -webkit-transition: all .35s;
    -moz-transition: all .35s;
    transition: all .35s;
}

.btn-default:hover,
.btn-default:focus,
.btn-default.focus,
.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
    border-color: #ededed;
    color: #222;
    background-color: #f2f2f2;
}

.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
    background-image: none;
}

.btn-default.disabled,
.btn-default[disabled],
fieldset[disabled] .btn-default,
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled.focus,
.btn-default[disabled].focus,
fieldset[disabled] .btn-default.focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
    border-color: #fff;
    background-color: #fff;
}

.btn-default .badge {
    color: #fff;
    background-color: #222;
}

.btn-primary {
    border-color: #f05f40;
    color: #fff;
    background-color: #f05f40;
    -webkit-transition: all .35s;
    -moz-transition: all .35s;
    transition: all .35s;
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary.focus,
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
    border-color: #ed431f;
    color: #fff;
    background-color: #ee4b28;
}

.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
    background-image: none;
}

.btn-primary.disabled,
.btn-primary[disabled],
fieldset[disabled] .btn-primary,
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled.focus,
.btn-primary[disabled].focus,
fieldset[disabled] .btn-primary.focus,
.btn-primary.disabled:active,
.btn-primary[disabled]:active,
fieldset[disabled] .btn-primary:active,
.btn-primary.disabled.active,
.btn-primary[disabled].active,
fieldset[disabled] .btn-primary.active {
    border-color: #f05f40;
    background-color: #f05f40;
}

.btn-primary .badge {
    color: #f05f40;
    background-color: #fff;
}

.btn {
    border: 0;
    border-radius: 300px;
    text-transform: uppercase;
    font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
    font-weight: 700;
}

.btn-xl {
    padding: 15px 30px;
}

::-moz-selection {
    text-shadow: none;
    color: #fff;
    background: #222;
}

::selection {
    text-shadow: none;
    color: #fff;
    background: #222;
}

img::selection {
    color: #fff;
    background: 0 0;
}

img::-moz-selection {
    color: #fff;
    background: 0 0;
}

body {
    webkit-tap-highlight-color: #222;
}


text:
title: Customizing Lock
description: This tutorial demonstrates how to customize the Lock widget
---

<%= include('../../../_includes/_package', {
  org: 'auth0-samples',
  repo: 'auth0-angularjs-sample',
  path: '10-Customizing-Lock',
  requirements: [
    'AngularJS 1.5.8',
    'angular-lock 2.0.2'
  ]
}) %>

Using Lock is easy, but you may want to customize your login UI. There are several options available for this.

## Lock Options

Some UI customization can be done via the `options` parameter when initializing a `lockProvider`.

## Theme Options

You can set custom theme properties, such as a different logo or primary color, by adding a `theme` property with custom values.

```js
// app.js

(function () {

  'use strict';

  angular
    .module('app', ['auth0.lock', 'angular-jwt', 'ui.router'])
    .config(config);

  function config(lockProvider) {

    lockProvider.init({
      clientID: '${account.clientId}',
      domain: '${account.namespace}',
      options: {
        theme: {
          logo: 'https://auth0.com/lib/homepage/img/logo-tmz.svg',
          primaryColor: "#b81b1c"
        }
      }
    });
  }

})();
```

**Note**: See the [theming options](https://github.com/auth0/lock#theming-options) documentation for more detail.

## Language Dictionary Specification

You can also customize the text that `Lock` will display with the `languageDictionary` option parameter:

```js
// app.js

(function () {

  'use strict';

  angular
    .module('app', ['auth0.lock', 'angular-jwt', 'ui.router'])
    .config(config);

  function config(lockProvider) {

    lockProvider.init({
      _idTokenVerification: false,
      clientID: '${account.clientId}',
      domain: '${account.namespace}',
      options: {
        languageDictionary: {
          title: "Log me in"
        }
      }
    });
  }

})();
```

> **Note**: See the [Language Dictionary Specification](https://github.com/auth0/lock#language-dictionary-specification) for more information.

This is how Lock will appear using a custom logo, color, and title:

![Custom lock](/media/articles/angularjs/widget-custom-logo-color.png)


text:
Library
=======

The library can be included

``` js
try {
   // for Node.js
   var autobahn = require('autobahn');
} catch (e) {
   // for browsers (where AutobahnJS is available globally)
}
```

Autobahn bundles whenjs and cryptojs. These bundled libraries can be accessed like

``` js
try {
   var autobahn = require('autobahn');
   var when = require('when');
   var crypto = require('crypto-js');
} catch (e) {
   var when = autobahn.when;
   var crypto = autobahn.crypto;
}
```

Library Version
---------------

**Autobahn|JS** library version is available (read-only):

    autobahn.version()

which returns a string.

Debug Mode
----------

To enable *debug mode*, define a global variable

    AUTOBAHN_DEBUG = true;

*before* including **Autobahn|JS**. Debug mode works for use both in the browser and in Node.js. When using **Autobahn|JS** in a browser, you'd do e.g.

``` html
<!DOCTYPE html>
<html>
   <body>
      <script>
         AUTOBAHN_DEBUG = true;
      </script>
      <script src="http://path_to_your_hosted_version_of_autobah/autobahn.min.jgz">
     </script>
   </body>
</html>
```

Connections
-----------

A new connection is created using

    autobahn.Connection(options)

which returns an autobahn connection object.

Example: **Create a new connection using WebSocket as a transport**

``` js
var connection = new autobahn.Connection({
                           url: 'ws://127.0.0.1:9000/',
                           realm: 'realm1'
                        });
```

This is the brief syntax which uses the default WebSocket transport and just gives a single connection URL. You can alternatively define a list of transports to try successively - see connection-options.

Connection Methods
------------------

To **open a connection**:

    autobahn.Connection.open()

This will establish an underlying transport and create a new session running over the transport. WebSocket is the default transport, but for environments which do not support WebSocket (like really old browsers) HTTP long-poll can be used as a fallback.

When the transport is lost, automatic reconnection will be attempted. This can be configured using the `options` provided to the constructor of the `Connection` (see [Connection Options](#connection-options)).

To **close a connection**:

    autobahn.connection.close(reason, message)

where both arguments are optional.

* `reason` is a *WAMP URI* providing a closing reason e.g. 'com.myapp.close.signout' to the server side. If no reason is given, the default URI `wamp.goodbye.normal` is sent.
* `message` is a *string*, to be used as a human-readable closing message

This returns a *string* on connection close error, else *undefined*.

When a connection has been closed explicitly, no automatic reconnection will happen.

Connection Callbacks
--------------------

`autobahn.Connection` provides two callbacks:

-   `autobahn.Connection.onopen`
-   `autobahn.Connection.onclose`

The **connection open callback** is fired when the connection has been established and a new session was created. This is the main callback which application code will hook into.

``` js
autobahn.Connection.onopen = function (session, details) {
   // Underlying transport to WAMP router established and new WAMP session started.
   // session is an instance of autobahn.Session
};
```

The **connection open callback** is passed the `autobahn.Session` object which has been created on opening the connection and a details object which contains further information about the session establishment such as the authentication role and ID assigned by the WAMP router.

The **connection close callback** is fired when the connection has been closed explicitly, was lost or could not be established in the first place.

``` js
autobahn.Connection.onclose = function (reason, details) {
   // connection closed, lost or unable to connect
};
```

`reason` is a string with the possible values

-   `"closed"`: The connection was closed explicitly (by the application or server). No automatic reconnection will be tried.
-   `"lost"`: The connection had been formerly established at least once, but now was lost. Automatic reconnection will happen **unless you return truthy** from this callback.
-   `"unreachable"`: The connection could not be established in the first place. No automatic reattempt will happen, since most often the cause is fatal (e.g. invalid server URL or server unreachable)
-   `"unsupported"`: No WebSocket transport could be created. For security reasons the WebSocket spec states that there should not be any specific errors for network-related issues, so no details are returned in this case either.

`details` is an object containing the `reason` and `message` passed to  `autobahn.Connection.close()`, and thus does not apply in case of `"lost"` or `"unreachable"`.

Connection Options
------------------

The constructor of `autobahn.Connection()` provides various options.

**Required** options:

-   `realm`: *string* - The WAMP realm to join, e.g. `realm1`
-   a target to connect to, for which there are two options:
    - `url`: *string* - the WebSocket URL of the WAMP router to connect to, e.g. `ws://myserver.com:8080/ws` via WebSocket, or
    - a list of transports to try successively

Supported transports are WebSocket and HTTP long-poll.

As an example, with the options below, **Autobahn|JS** first attempts to establish a WebSocket connection and if this fails a HTTP long-poll connection to the respective URLs given.

``` js
var connection = new autobahn.Connection({
   transports: [
      {
         'type': 'websocket',
         'url': 'ws://127.0.0.1:9000/ws'
      },
      {
         'type': 'longpoll',
         'url': 'http://127.0.0.1:9000/lp'
      }
   ],
   realm: 'realm1'
});
```

Not all WAMP routers support all transports, so take a look at the documentation for your router. (The above configuration with both WebSocket and HTTP long-poll on the same port is something which Crossbar.io allows.)

> **note**
>
> We recommend that you use encrypted connections (using TLS). On the client side in **Autobahn|JS**, do this by setting the schema part of the connection URL to `wss` instead of `ws`.

> **note**
>
> When a Web page is served encrypted, then WebSocket connections from the page are also required to be encrypted. The WebSocket spec does intentionally not define any error message for this case, so **Autobahn|JS** returns `unsupported`.

**Optional** options:

Options that control what **kind of Deferreds** to use:

-   `use_es6_promises`: *boolean* - use deferreds based on ES6 promises
-   `use_deferred`: *callable* - if provided, use this deferred constructor, e.g. `jQuery.Deferred` or `Q.defer`, if omitted [when.js](https://github.com/cujojs/when) is used (see their documentation for information on the full range of features)

> **note**
>
> Using ES6-based promises has certain restrictions. E.g. no progressive call results are supported. In general, unless there is a good technical reason, the default deferreds should be used.

Options that control **automatic reconnection**:

-   `max_retries`: *integer* - Maximum number of reconnection attempts. Unlimited if set to -1 (default: **15**)
-   `initial_retry_delay`: *float* - Initial delay for reconnection attempt in seconds (default: **1.5**).
-   `max_retry_delay`: *float* - Maximum delay for reconnection attempts in seconds (default: **300**).
-   `retry_delay_growth`: *float* - The growth factor applied to the retry delay between reconnection attempts (default: **1.5**).
-   `retry_delay_jitter`: *float* - The standard deviation of a Gaussian to jitter the delay on each retry cycle as a fraction of the mean (default: **0.1**).

Options that control **WebSocket subprotocol handling**:

-   `skip_subprotocol_check`: Not yet implemented.
-   `skip_subprotocol_announce`: Not yet implemented.

Options that control **WebSocket heartbeat on NodeJS**:

> **note**
>
> Below options only work when the transport is `websocket` and the underlying platform is NodeJS/Electron.

-   `autoping_interval`: Seconds between automatic pings
-   `autoping_timeout`: Seconds until a ping is considered timed-out
-   `autoping_size`: bytes of random data to send in ping messages (default: 4)

Options that define **Custom error handlers:**
-   `on_user_error`: *function* - This error handler is called in the following cases:
    - an exception raised in `onopen`, `onclose`, `onchallenge` callbacks,
    - an exception raised in the event handler in the subscriber role,
    - an error occurred in the invocation handler in the callee role (the handler called in the client, before
      the error message is sent back to the Dealer.)
-   `on_internal_error`: *function* - This error handler is called in the following cases:
    - not able to create a Wamp transport,
    - when a protocol violation is occurred,
    - when no `onchallenge` defined, but a challenge request is received due to authenticate the client,

```javascript
    var connection = new autobahn.Connection({
       on_user_error: function (error, customErrorMessage) {
           // here comes your custom error handling, when a
           // something went wrong in a user defined callback.
        },
        on_internal_error: function (error, customErrorMessage) {
           // here comes your custom error handling, when a
           // something went wrong in the autobahn core.
        }
        // ... other options
    });

```

> **note**
>
> If no error handler is defined for these functions, an error level console log will be written.

> **note**
>
> In a case of error handling in the Callee role, when the invocation handler is executed, the error
> is reported on the Callee side (with the custom error handler or an error log), but despite that the
> error is sent back to the Dealer, and the Caller will receive a `runtime.error` wamp message.

 Options that control **tls connection**:
 -   `tlsConfiguration`: *object*
     - `ca`: *Buffer | String* - CA
     - `cert`: *Buffer | String* - Certificate Public Key
     - `key`: *Buffer | String* - Certificate Private Key

Connection Properties
---------------------

To get the session object if there is a session currently running over the connection:

    Connection.session

which returns an instance of `autobahn.Session` if there is a session currently running on the connection.

To check whether the connection (the underlying transport for the session) has been established:

    Connection.isConnected

which returns `true` if the Connection is open.

A read-only property that signals if the **underlying session is open** and attached to a realm:

    Connection.isOpen

which returns `true` if the underlying session is open.

To check whether the connection is currently in a "try to reconnect" cycle:

    Connection.isRetrying

which returns `true` if reconnects are being attempted.

A property which holds a transport instance when connected

    Connection.transport

which holds a transport instance when connected.

    Connection.transport.info.type

which returns `websocket`, `rawsocket` or `longpoll`

    Connection.transport.info.url

which returns the URL the transport is connected to

    Connection.transport.info.protocol

the WAMP protocol in use, e.g. `wamp.2.json`

A property with the **Deferred factory** in use on this connection:

    Connection.Deferred

returns the Deferred factory function used by the connection.

A Deferred factory for the type of Deferreds (whenjs, ES6, jQuery or Q) in use with the connection:

    Connection.defer()

which returns a Deffered of the type specified in the call to the connection constructor.

Sessions
========

WAMP sessions are instances of `autobahn.Session` that are created by connections:

``` js
var connection = new autobahn.Connection({
                           url: 'ws://127.0.0.1:9000/',
                           realm: 'realm1'
                        });

connection.onopen = function (session) {

   // session is an instance of autobahn.Session

};

connection.open();
```

Session Properties
------------------

Session objects provide a number of properties.

A read-only property with the WAMP **session ID** as an integer:

    Session.id

A read-only property with the **realm** (as a string) the session is attached to:

    Session.realm

A read-only property that signals if the **session is open** (as a boolean) and attached to a realm:

    Session.isOpen

A read-only property with the **features** (as an object) from the WAMP Advanced Profile available on this session (supported by both peers):

    Session.features

A read-only property with an array of all currently **active subscriptions** on this session:

    Session.subscriptions

A read-only property with an array of all currently **active registrations** on this session:

    Session.registrations

A property with the **Deferred factory** in use on this session:

    Session.defer

A Deferred factory for the type of Deferreds (whenjs, ES6, jQuery or Q) in use with the session:

    Session.defer()

Session Logging
---------------

**Autobahn|JS** includes a logging method for convenient logging from sessions.

    Session.log(output)

This can be assigned as an event handler when no `output` argument is used.

`session.log` can be used without an `output` argument when it is assigned as an event handler.

For example:

``` js
connection.onopen = function (session) {

   session.log("Session open.");

   session.call('com.timeservice.now').then(
         session.log;
   );
};
```

which will log to the console:

    WAMP session 2838853860563188 on 'realm1' at 3.902 ms
       Session open.
    WAMP session 2838853860563188 on 'realm1' at 4.679 ms
       2014-03-13T14:09:07Z

where `2014-03-13T14:09:07Z` is the return value of the call to `com.timeservice.now`.

The log method will log the WAMP session ID and the realm of the session, as well as a timestamp that provides the time elapsed since the *construction* of the `autobahn.Session` object.

URI Shortcuts
-------------

Establish an URI prefix to be used as a shortcut in WAMP interactions on `session`:

    Session.prefix(shortcut, prefix)

where

* `shortcut` is a *string*
* `prefix` is an URI part

> **note**
>
> URI prefixes must only contain full URI components, i.e. stop at a '.' separation of an URI. 'com.myapp.topics' is a valid prefix if it is to be used as part of full URI 'com.myapp.topics.one', but invalid if it is intended to be combined with a suffix to form 'com.myapp.topicsnew'.

**Example**:

``` js
session.prefix('api', 'com.myapp.service');
```

You can then use [CURIEs](http://en.wikipedia.org/wiki/CURIE) in addition to URIs:

``` js
session.call('api:add2').then(...);
```

which is equivalent to

``` js
session.call('com.myapp.service.add2').then(...);
```

To remove a prefix:

``` js
session.prefix('api', null);
```

To resolve a prefix *(normally not needed in user code)*:

``` js
session.resolve('api:add2');
```

Session Meta-Events & Procedures
--------------------------------

Some WAMP routers (such as [Crossbar.io](http://crossbar.io)) provide the possibility to subscribe to events which are created by the router based on session lifecycle, as well as procedures which allow the retrieval of information about current sessions. For more information see the [Crossbar.io documentation](http://crossbar.io/docs/Session-Metaevents-and-Procedures/).

Subscribe
=========

To subscribe to a topic on a `session`:

    Session.subscribe(topic, handler, options)

where

* `topic` is the URI of the topic to subscribe to
* `handler` is the event handler which should consume events
* `options` - options object (see below)

The `handler` must be a callable

    function (args, kwargs, details)

where

1.  `args` is an array with event payload
2.  `kwargs` is an object with event payload
3.  `details` is an object which provides event metadata

Example: **Subscribe to a topic**

``` js
function on_event1(args, kwargs, details) {
   // event received, do something ..
}

session.subscribe('com.myapp.topic1', on_event1).then(
   function (subscription) {
      // subscription succeeded, subscription is an instance of autobahn.Subscription
   },
   function (error) {
      // subscription failed, error is an instance of autobahn.Error
   }
);
```

or, differently notated, but functionally equivalent

``` js
var d = session.subscribe('com.myapp.topic1', on_event1);

d.then(
   function (subscription) {
      // subscription succeeded, subscription is an instance of autobahn.Subscription
   },
   function (error) {
      // subscription failed, error is an instance of autobahn.Error
   }
);
```

Complete Examples:

-   [PubSub Basic](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/pubsub/basic)

Pattern-Based Subscriptions
--------------------------

As a default, topic URIs in subscriptions are matched exactly.

It is possible to change the matching policy to either `prefix` or `wildcard` matching via an option when subscribing, e.g.

``` js
session.subscribe('com.myapp', on_event_all, { match: 'prefix' })
session.subscribe('com.myapp..update', on_event_update, { match: 'wildcard' })
```

In the first case, events for all publications where the topic contains the prefix `com.myapp` will be received, in the second events for all publications which match the wildcard pattern, e.g. `com.myapp.user121.update` and `com.myapp.sensor_23.update`.

Active Subscriptions
--------------------

A list of subscriptions (in no particular order) currently active on a `session` may be accessed via :jsSession.subscriptions.

This returns an array of `autobahn.Subscription` objects. E.g.

``` js
var subs = session.subscriptions;
for (var i = 0; i < subs.length; ++i) {
   console.log("Active subscription with ID " + subs[i].id);
}
```

> **note**
>
> Caution: This property and the subscription objects returned should be considered read-only. DO NOT MODIFY.

Unsubscribing
-------------

You can unsubscribe a previously established `subscription`

    Session.unsubscribe(subscription)

where `subscription` is an instance of `autobahn.Subscription` and which returns a *promise* that resolves to a boolean when successful or rejects with an instance of `autobahn.Error` when unsuccessful.

> **note**
>
> If successful, the boolean returned indicates whether the underlying WAMP subscription was actually ended (`true`) or not, since there still are application handlers in place due to multiple client-side subscriptions for the same WAMP subscription to the broker.

Example: **Unsubscribing a subscription**

``` js
var sub1;

session.subscribe('com.myapp.topic1', on_event1).then(
   function (subscription) {
      sub1 = subscription;
   }
);

...

session.unsubscribe(sub1).then(
   function (gone) {
      // successfully unsubscribed sub1
   },
   function (error) {
      // unsubscribe failed
   }
);
```

Complete Examples:

-   [PubSub Unsubscribe](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/pubsub/unsubscribe)

Subscription Meta-Events and Procedures
---------------------------------------

Some WAMP routers (such as [Crossbar.io](http://crossbar.io)) provide the possibility to subscribe to events which are created by the router based on subscription lifecycle, as well as procedures which allow the retrieval of information about current subscriptions. For more information see the [Crossbar.io documentation](http://crossbar.io/docs/Subscription-Meta-Events-and-Procedures/).

Publish
=======

To publish an event on a `session`:

    Session.publish(topic, args, kwargs, options)

where

* `topic` is the URI of the topic to publish to
* `args` is an *optional* array as application event payload
* `kwargs` is an *optional* object as application event payload
* `options` is an *optional* object which specifies options for publication (see below)

and which returns a *promise* if `options.acknowledge` is set, else nothing.

Examples: **Publish an event**

``` js
session.publish('com.myapp.hello', ['Hello, world!']);
```

``` js
session.publish('com.myapp.hello', [], { text: 'Hello, world' })
```

Complete Examples:

-   [PubSub Basic](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/pubsub/basic)
-   [PubSub Complex Payload](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/pubsub/complex)

Acknowledgement
---------------

By default, a publish is not acknowledged by the *Broker*, and the *Publisher* receives no feedback whether the publish was indeed successful or not.

If supported by the *Broker*, a *Publisher* may request acknowledgement of a publish via the option `acknowledge` set to `true`.

With acknowledged publish, the publish method will return a promise that will resolve to an instance of `autobahn.Publication` when the publish was successful, or reject with an `autobahn.Error` when the publish was unsuccessful.

Example: **Publish with acknowledge**

``` js
session.publish('com.myapp.hello', ['Hello, world!'], {}, {acknowledge: true}).then(
   function (publication) {
      // publish was successful
   },
   function (error) {
      // publish failed
   };
);
```

Receiver Black-/Whitelisting
----------------------------

If the feature is supported by the *Broker*, a *Publisher* may restrict the actual receivers of an event beyond those subscribed via the options

-   `exclude`
-   `eligible`

`exclude` is an array of WAMP session IDs providing an explicit list of (potential) *Subscribers* that won't receive a published event, even though they might be subscribed. In other words, `exclude` is a blacklist of (potential) *Subscribers*.

`eligible` is an array of WAMP session IDs providing an explicit list of (potential) *Subscribers* that are allowed to receive a published event. In other words, `eligible` is a whitelist of (potential) *Subscribers*.

The *Broker* will dispatch events published only to *Subscribers* that are not explicitly excluded via `exclude` **and** which are explicitly eligible via `eligible`.

Example: **Publish with exclude**

``` js
session.publish('com.myapp.hello', ['Hello, world!'], {}, {exclude: [123, 456]});
```

The event will be received by all *Subscribers* to topic `com.myapp.hello`, but not the sessions with IDs `123` and `456` (if those sessions are subscribed anyway).

Example: **Publish with eligible**

``` js
session.publish('com.myapp.hello', ['Hello, world!'], {}, {eligible: [123, 456]});
```

The event will be received by the sessions with IDs `123` and `456`, if those sessions are subscribed to topic `com.myapp.hello`.

Publisher Exclusion
-------------------

By default, a *Publisher* of an event will not itself receive an event published, even when subscribed to the topic the *Publisher* is publishing to.

If supported by the *Broker*, this behavior can be overridden via the option `exclude_me` set to `false`.

Example: **Publish without excluding publisher**

``` js
session.publish('com.myapp.hello', ['Hello, world!'], {}, {exclude_me: false});
```

Register
========

To register a procedure on a `session` for remoting:

    Session.register(procedure, endpoint, options)

where

* procedure is the URI of the procedure to register
* endpoint is the function that provides the procedure implementation
* options is an *optional* object which specifies options for registration (see below)

and which returns a *promise* that resolves to an instance of `autobahn.Registration` when successful, or rejects with an instance of `autobahn.Error` when unsuccessful.

The `endpoint` must be a callable

> function (args, kwargs, details)

where

1.  `args` is an array with call arguments
2.  `kwargs` is an object with call arguments
3.  `details` is an object which provides call metadata

and which returns either a plain value or a promise, and the value is serializable or an instance of `autobahn.Result`.

The `autobahn.Result` wrapper is used when returning a complex value (multiple positional return values and/or keyword return values).

Example: **Register a procedure**

``` js
function myproc1(args, kwargs, details) {
   // invocation .. do something and return a plain value or a promise ..
}

session.register('com.myapp.proc1', myproc1).then(
   function (registration) {
      // registration succeeded, registration is an instance of autobahn.Registration
   },
   function (error) {
      // registration failed, error is an instance of autobahn.Error
   }
);
```

When the procedure which you are registering works asynchronous, you can return a promise which is resolved when the asynchronous part has completed:

``` js
function myAsyncFunction(args, kwargs, details) {
   var d = new autobahn.when.defer();

   setTimeout(function() {
      d.resolve("async finished");
   }, 1000);

   return d.promise;
}
```

The above example uses the default promises library for AutobahnJS, when. The syntax may vary for other libraries.

Complete Examples:

-   [RPC Time Service](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/timeservice)
-   [RPC Arguments](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/arguments)
-   [RPC Complex Result](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/complex)
-   [RPC Slow Square](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/slowsquare)

Pattern-Based Registrations
---------------------------

As a default, URIs in registrations are matched exactly.

It is possible to change the matching policy to either `prefix` or `wildcard` matching via an option when registering, e.g.

``` js
session.register('com.myapp', handle_all, { match: 'prefix' })
```

or

``` js
session.register('com.myapp..update', handle_updates, { match: 'wildcard' })
```

In the first case, calls for where the URI contains the prefix `com.myapp` will lead to the callee being invoked, while in the second calls where the URI matches the wildcard pattern will lead to the callee being invoked, e.g. `com.myapp.user121.update` and `com.myapp.sensor_23.update`.

Shared Registrations
--------------------

As a default, only a single registration per URI is allowed, with an existing registration blocking all subsequent attempts.

It is possible to have shared registrations, i.e. more than one registration for an URI. This does not change the fact that only a single calle is invoked for each call. There are four invocation rules which determine how a callee is determined:

-   `first` - first registration in the list is invoked
-   `last` - last registration in the list is invoked
-   `roundrobin` - the registration following the last invoked registration on the list is invoked
-   `random` - a random registration from the list is invoked

The invocation policy for an URI is determined by the first registration for that URI, and only subsequent registration attemps which set the same invocation rule may be successful. For example, with a first registration of

``` js
session.register('com.myapp.procedure1', handle_all, { invoke: 'random' })
```

any subsequent registration which does not set `invoke: 'random'` will be rejected.

Active Registrations
--------------------

A list of registrations (in no particular order) currently active on a `session` may be accessed like via `Session.registrations`.

This returns an array of `autobahn.Registration` objects. E.g.

``` js
var regs = session.registrations;
for (var i = 0; i < regs.length; ++i) {
   console.log("Active registration with ID " + regs[i].id);
}
```

> **note**
>
> Caution: This property and the registration objects returned should be considered read-only. DO NOT MODIFY.

Unregistering
-------------

You can unregister a previously established `registration`

    Session.unregister(registration)

where registration is an instance of autobahn.Registration and which returns a *promise* that resolves with no value when successful or rejects with an instance of ``autobahn.Error`` when unsuccessful.

Example: **Unregistering a registration**

``` js
var reg1;

session.register('com.myapp.proc1', myproc1).then(
   function (registration) {
      reg1 = registration;
   }
);

...

session.unregister(reg1).then(
   function () {
      // successfully unregistered reg1
   },
   function (error) {
      // unregister failed
   }
);
```

Registration Meta-Events and Procedures
---------------------------------------

Some WAMP routers (such as [Crossbar.io](http://crossbar.io)) provide the possibility to subscribe to events which are created by the router based on registration lifecycle, as well as procedures which allow the retrieval of information about current registrations. For more information see the [Crossbar.io documenation](http://crossbar.io/docs/Registration-Meta-Events-and-Procedures/).

Call
====

To call a remote procedure from a `session`:

    Session.call(procedure, args, kwargs, options)

where

* `procedure` is the URI of the procedure to call
* `args` is an *optional* optional array of call arguments
* `kwargs` is an *optional* object of call arguments
* `options` is an *optional* object with options for the call (see below)

and which returns a *promise* that will resolve to the call result if successful (either a plain value or an instance of `autobahn.Result`) or reject with an instance of `autobahn.Error`.

Example: **Call a procedure**

``` js
session.call('com.arguments.add2', [2, 3]).then(
   function (result) {
      // call was successful
   },
   function (error) {
      // call failed
   }
);
```

Complete Examples:

-   [RPC Time Service](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/timeservice)
-   [RPC Arguments](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/arguments)
-   [RPC Complex Result](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/complex)
-   [RPC Slow Square](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/slowsquare)

Errors
------

On an error with a PRC call, a error object is passed to the error handler defined in the call. This has three properties:

-   error URI
-   an array of error arguments
-   an object with error arguments

Throwing an error in a registered procedure can happen in one of two ways:

-   by defining an array of error arguments
-   by creating a `autobahn.Error` object

In the first case, the `error URI` is set to a default value, and the object of error arguments remains emtpy, i.e. if you do

``` js
throw ['this is just an error', 'with an array of arguments'];
```

logging this in the caller will come out something like

    wamp.error.runtime_error ["this is just an error", "with an array of arguments"] Object {}

When defining an `autobahn.Error` object, all three properties can be defined. I.e. doing

``` js
throw new autobahn.Error('com.myapp.error', ['this is a more complex error'], {a: 23, b: 9});
```

and logging this in the caller will lead to something like

    com.myapp.error ['this is a more complex error'] Object {a: 23, b: 9}

Complete Examples:

-   [RPC Errors](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/errors)

Progressive Results
-------------------

Instead of returning just a single, final result, a remote procedure can return progressive results, if this is requested by the caller.

Progressive results are part of the advanced spec for WAMP, and may not be supported by all WAMP routers.

An example for a call requesting progressive call results would be

``` js
session.call('com.myapp.longop', [10], {}, {receive_progress: true}).then(
   function (res) {
      console.log("Final:", res);
      connection.close();
   },
   function (err) {
   },
   function (progress) {
      console.log(progress);
   }
);
```

Here a third callback has been added, which is fired on each receipt of a progressive result event.

In the backend, the function for returning progressive results could be something like

``` js
if (details.progress) {
   for (var i = 0; i < 5; i++) {
      details.progress(i);
   }
   return "progressive result"
} else {
   return "single result";
}
```

which would return 5 progressive result events (each with the current value of `i` as the payload) before returning `"progressive result"` as the final result.

Complete Examples:

-   [RPC Progress](https://github.com/crossbario/autobahn-python/tree/master/examples/twisted/wamp/rpc/progress)

Caller Identification
---------------------

If the feature is supported by the *Dealer*, a *Caller* may request the disclosure of its identity (its WAMP session ID) to the invoked *Callee* via the option `disclose_me` set to `true`.

Example: **Call with caller disclosure**

``` js
session.call('com.myapp.procedure1', ['Hello, world!'], {}, {disclose_me: true});
```

If the *Dealer* allows the disclosure, the callee can consume the *Caller's* session ID like this:

``` js
function on_call(args, kwargs, details) {
  // details.caller provides the Publisher's WAMP session ID
}

session.register(on_call, 'com.myapp.procedure1');
```


text:
#include <Boots/Network/smtp.hpp>
#include <Boots/Utils/exception.hpp>
#include <Boots/Utils/string.hpp>

using namespace std;

/*
 * Smtp::Mail
 */
void        Smtp::Mail::SetSender(const std::string& address, const std::string& name)
{
  sender.address = address;
  sender.name    = name;
}

void        Smtp::Mail::AddRecipient(const std::string& address, const std::string& name, unsigned char flags)
{
  Recipient recipient;

  recipient.address = address;
  recipient.name    = name;
  recipient.type    = flags;
  recipients.push_back(recipient);
}

void        Smtp::Mail::DelRecipient(const std::string& address)
{
  auto it = std::find(recipients.begin(), recipients.end(), address);

  if (it != recipients.end())
    recipients.erase(it);
}

/*
 * Smtp::Server
 */
Smtp::Server::Server()
{
}

void Smtp::Server::Connect(const std::string& hostname, unsigned short port)
{
  if (Network::Socket::Connect(hostname, port))
    SmtpHandshake();
  else
    Exception<Smtp::Server>::Raise("Cannot connect to " + hostname);
  if (tls_enabled)
    SmtpStartTls();
}

void Smtp::Server::Connect(const std::string& hostname, unsigned short port, const std::string& username, const std::string& password, AuthenticationProtocol protocol)
{
  Connect(hostname, port);
  (this->*auth_methods[protocol])(username, password);
}

void Smtp::Server::Disconnect(void)
{
  SmtpQuit();
  Network::Socket::Disconnect();
}

void Smtp::Server::Send(const Smtp::Mail& mail)
{
  SmtpNewMail(mail);
  SmtpRecipients(mail);
  SmtpBody(mail);
}

/*
 * SMTP Protocol Implementation (RFC 5321)
 */
std::string Smtp::Server::SmtpReadAnswer(unsigned short expected_return)
{
  std::string    answer;
  unsigned short return_value;

  WaitForData();
  NetworkRead();
  *this >> answer;
  return_value = atoi(answer.substr(0, 3).c_str());
  if (return_value != expected_return)
  {
    std::stringstream error_message;

    error_message << "Expected answer status to be " << expected_return << ", received `" << answer << '`';
    Exception<Smtp::Server>::Raise(error_message.str());
  }
  return (answer);
}

void Smtp::Server::SmtpBody(const Smtp::Mail& mail)
{
  // Notify that we're starting the DATA stream
  *this << "DATA\r\n";
  NetworkWrite();
  SmtpReadAnswer(354);
  // Setting the headers
  SmtpDataAddresses("To",       mail, 0);
  SmtpDataAddresses("Cc",       mail, Smtp::Mail::CarbonCopy);
  SmtpDataAddresses("Bcc",      mail, Smtp::Mail::CarbonCopy | Smtp::Mail::Blind);
  SmtpDataAddress  ("Reply-To", mail.GetReplyTo(),        "");
  SmtpDataAddress  ("From",     mail.GetSender().address, mail.GetSender().name);
  // Send the subject
  *this << "Subject: " << mail.GetSubject() << "\r\n";
  // Send the body and finish the DATA stream
  *this << mail.body   << "\r\n.\r\n";
  NetworkWrite();
  SmtpReadAnswer();
}

void Smtp::Server::SmtpDataAddresses(const std::string& field, const Smtp::Mail& mail, int flag)
{
  auto it  = mail.recipients.begin();
  auto end = mail.recipients.end();
  int  i   = 0;

  for (; it != end ; ++it)
  {
    if (it->type == flag)
    {
      if (i != 0)
        *this << ", ";
      else
        *this << field << ": ";
      if (it->name.size() > 0)
        *this << it->name << " <" << it->address << ">";
      else
        *this << it->address;
      ++i;
    }
  }
}

void Smtp::Server::SmtpDataAddress(const std::string& field, const std::string& address, const std::string& name)
{
  *this << field << ": " << address;
  if (name.size() > 0)
    *this << " <" << name << ">";
  *this << "\r\n";
}

void Smtp::Server::SmtpRecipients(const Smtp::Mail& mail)
{
  auto it  = mail.recipients.begin();
  auto end = mail.recipients.end();

  for (; it != end ; ++it)
  {
    *this << "RCPT TO: " << it->address << "\r\n";
    NetworkWrite();
    SmtpReadAnswer();
  }
}

void Smtp::Server::SmtpNewMail(const Smtp::Mail& mail)
{
  const Smtp::Mail::Sender& sender = mail.GetSender();

  *this << "MAIL FROM: " << sender.address << "\r\n";
  NetworkWrite();
  SmtpReadAnswer();
}

void Smtp::Server::SmtpHandshake()
{
  std::stringstream command;

  // Receiving the server identification
  server_id = SmtpReadAnswer(220);
  // Sending handshake
  command << "HELO " << Ip() << "\r\n";
  *this << command.str();
  NetworkWrite();
  SmtpReadAnswer(250);
}

void Smtp::Server::SmtpQuit()
{
  *this << "QUIT\r\n";
  NetworkWrite();
  SmtpReadAnswer(221);
}

/*
 * SMTP StartTLS (RFC 2487) (TLS protocol is defined in RFC2246)
 */
void Smtp::Server::StartTls(void)
{
  tls_enabled = true;
}

void Smtp::Server::SmtpStartTls(void)
{
  *this << "STARTTLS" << "\r\n";
  NetworkWrite();
  SmtpReadAnswer(220);
}

/*
 * SMTP Authentication Extension (RFC 2554)
 */
std::map<Smtp::Server::AuthenticationProtocol,Smtp::Server::SmtpAuthMethod> Smtp::Server::auth_methods = {
  { Smtp::Server::PLAIN,      &Smtp::Server::SmtpAuthPlain     },
  { Smtp::Server::LOGIN,      &Smtp::Server::SmtpAuthLogin     },
  { Smtp::Server::MD5,        &Smtp::Server::SmtpAuthMd5       },
  { Smtp::Server::DIGEST_MD5, &Smtp::Server::SmtpAuthDigestMd5 },
  { Smtp::Server::CRAM_MD5,   &Smtp::Server::SmtpAuthCramMd5   }
};

void Smtp::Server::SmtpAuthPlain(const std::string& user, const std::string& password)
{
  string auth_hash = String::base64_encode('\000' + user + '\000' + password);

  *this << "AUTH PLAIN " << auth_hash << "\r\n";
  NetworkWrite();
  SmtpReadAnswer(235);
}

void Smtp::Server::SmtpAuthLogin(const std::string& user, const std::string& password)
{
  string user_hash = String::base64_encode(user);
  string pswd_hash = String::base64_encode(password);

  *this << "AUTH LOGIN\r\n";
  NetworkWrite();
  SmtpReadAnswer(334);
  *this << user_hash << "\r\n";
  NetworkWrite();
  SmtpReadAnswer(334);
  *this << pswd_hash << "\r\n";
  NetworkWrite();
  SmtpReadAnswer(235);
}

void Smtp::Server::SmtpAuthMd5(const std::string& user, const std::string& password)
{
  throw "unsupported";
}

void Smtp::Server::SmtpAuthDigestMd5(const string& user, const string& password)
{
  throw "unsupported";
}

void Smtp::Server::SmtpAuthCramMd5(const string& user, const string& password)
{
  throw "unsupported";
}

// END SMTP AUTHENTICATION EXTENSION


text:
using Newtonsoft.Json;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace Sif.Framework.Service.Serialisation
{
    /// <summary>
    /// A serialiser that serialises an object to XML and then JSON, and deserialises JSON to XML and
    /// then an object.
    /// </summary>
    /// <typeparam name="T">Type of the object to serialise/deserialise.</typeparam>
    internal class XmlToJsonSerialiser<T> : ISerialiser<T>
    {
        private readonly XmlSerialiser<T> xmlSerialiser;

        /// <summary>
        /// Create an instance of this class.
        /// </summary>
        public XmlToJsonSerialiser()
        {
            xmlSerialiser = new XmlSerialiser<T>();
        }

        /// <summary>
        /// Create an instance of this class, specifying the root element of the serialised object (using an XML root
        /// attribute).
        /// </summary>
        /// <param name="root">XML root attribute.</param>
        public XmlToJsonSerialiser(XmlRootAttribute root)
        {
            xmlSerialiser = new XmlSerialiser<T>(root);
        }

        /// <summary>
        /// <see cref="ISerialiser{T}.Deserialise(Stream)"/>
        /// </summary>
        public T Deserialise(Stream stream)
        {
            T obj = default(T);

            if (stream != null)
            {
                using (StreamReader streamReader = new StreamReader(stream))
                {
                    string json = streamReader.ReadToEnd();

                    // If there is JSON data, deserialise into an object.
                    if (!string.IsNullOrWhiteSpace(json))
                    {
                        // Convert the JSON string into an XML document.
                        XmlDocument xmlDocument = JsonConvert.DeserializeXmlNode(json);

                        using (XmlReader xmlReader = new XmlNodeReader(xmlDocument))
                        {
                            // Deserialise the XML document into an object.
                            obj = (T)xmlSerialiser.Deserialize(xmlReader);
                        }
                    }
                }
            }

            return obj;
        }

        /// <summary>
        /// <see cref="ISerialiser{T}.Deserialise(string)"/>
        /// </summary>
        public T Deserialise(string str)
        {
            T obj = default(T);

            if (!string.IsNullOrWhiteSpace(str))
            {
                using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(str)))
                {
                    obj = Deserialise(stream);
                }
            }

            return obj;
        }

        /// <summary>
        /// <see cref="ISerialiser{T}.Serialise(T)"/>
        /// </summary>
        public string Serialise(T obj)
        {
            string str = null;

            if (obj != null)
            {
                Serialise(obj, out Stream stream);
                stream.Position = 0;

                using (StreamReader reader = new StreamReader(stream))
                {
                    str = reader.ReadToEnd();
                }
            }

            return str;
        }

        /// <summary>
        /// <see cref="ISerialiser{T}.Serialise(T, out Stream)"/>
        /// </summary>
        public void Serialise(T obj, out Stream stream)
        {
            stream = new MemoryStream();

            if (obj != null)
            {
                using (Stream serialiseStream = new MemoryStream())
                {
                    string xml;

                    using (StringWriter stringWriter = new StringWriter())
                    {
                        using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter))
                        {
                            // Serialise the object into an XML string.
                            xmlSerialiser.Serialize(xmlWriter, obj);
                            xml = stringWriter.ToString();
                        }
                    }

                    // Parse the XML string and remove empty elements (defined by the "xsi:nil" element).
                    XElement xElement = XElement.Parse(xml);
                    xElement
                        .Descendants()
                        .Where(x =>
                            string.IsNullOrEmpty(x.Value) &&
                            x.Attributes().Where(y => y.Name.LocalName == "nil" && y.Value == "true").Count() > 0)
                        .Remove();
                    xml = xElement.ToString();

                    // Convert the XML document into a JSON string.
                    XmlDocument xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(xml);
                    string json = JsonConvert.SerializeXmlNode(xmlDocument);

                    // Write the JSON string to the stream.
                    byte[] buf = System.Text.Encoding.Default.GetBytes(json);
                    stream.Write(buf, 0, buf.Length);
                    stream.Flush();
                }
            }
        }
    }
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
  ~
  ~ WSO2 Inc. licenses this file to you under the Apache License,
  ~ Version 2.0 (the "License"); you may not use this file except
  ~ in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing,
  ~ software distributed under the License is distributed on an
  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  ~ KIND, either express or implied. See the License for the
  ~ specific language governing permissions and limitations
  ~ under the License.
  -->

<artifact name="Eventstream_droneStats" version="1.0.0" type="event/stream" serverRole="DataAnalyticsServer">
	<file>org.wso2.iot.devices.droneStats_1.0.0.json</file>
</artifact>


text:
package com.github.tkerber.tempest;

import java.util.Map;

/**
 * Keeps track of the items being synchronised.
 */
public class SyncList{

    /**
     * The actual sync "list".
     *
     * Map the mountprefix to a mapping of paths to SyncItems.
     */
    private Map<String, Map<String, SyncItem>> sl;

    /**
     * Adds a file to the synclist, selecting an appropriate mountprefix.
     * @param file The path of the file to add to the synclist.
     * @param si The sync setting for this individual item.
     */
    public void add(String file, SyncItem i){
        // TODO
    }

    /**
     * Adds a file from the synclist.
     * @param mountprefix The file's mountprefix.
     * @param file The file path, relative to the mountprefix.
     * @param si The sync settings for this individual item.
     */
    public void add(String mountprefix, String file, SyncItem i){
        // TODO
    }

    /**
     * Removes a file from the synclist, selecting an appropriate mountprefix.
     * @param file The path of the file to remove from the synclist.
     */
    public void remove(String file){
        // TODO
    }

    /**
     * Removes a file from the synclist.
     * @param mountprefix The file's mountprefix.
     * @param file The file path, relative to the mountprefix.
     */
    public void remove(String mountprefix, String file){
        // TODO
    }

}