A Support Vector Machine (SVM) is a very powerful and versatile Machine Learning method, capable of performing linear or nonlinear classification, regression, and even outlier detection. It is one of the most popular models in Machine Learning, and anyone interested in Machine Learning should have it in their toolbox. SVMs are particularly well suited for classification of complex but small-sized or medium-sized datasets.
The case with two well-separated classes only can be understood in an intuitive way in terms of lines in a two-dimensional space separating the two classes (see figure below).
The basic mathematics behind the SVM is however less familiar to most of us. It relies on the definition of hyperplanes and the definition of a margin which separates classes (in case of classification problems) of variables. It is also used for regression problems.
With SVMs we distinguish between hard margin and soft margins. The latter introduces a so-called softening parameter to be discussed below. We distinguish also between linear and non-linear approaches. The latter are the most frequent ones since it is rather unlikely that we can separate classes easily by say straight lines.
The theory behind support vector machines (SVM hereafter) is based on the mathematical description of so-called hyperplanes. Let us start with a two-dimensional case. This will also allow us to introduce our first SVM examples. These will be tailored to the case of two specific classes, as displayed in the figure here based on the usage of the petal data.
We assume here that our data set can be well separated into two domains, where a straight line does the job in the separating the two classes. Here the two classes are represented by either squares or circles.
from sklearn import datasets
from sklearn.svm import SVC, LinearSVC
from sklearn.linear_model import SGDClassifier
from sklearn.preprocessing import StandardScaler
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
iris = datasets.load_iris()
X = iris["data"][:, (2, 3)] # petal length, petal width
y = iris["target"]
setosa_or_versicolor = (y == 0) | (y == 1)
X = X[setosa_or_versicolor]
y = y[setosa_or_versicolor]
C = 5
alpha = 1 / (C * len(X))
lin_clf = LinearSVC(loss="hinge", C=C, random_state=42)
svm_clf = SVC(kernel="linear", C=C)
sgd_clf = SGDClassifier(loss="hinge", learning_rate="constant", eta0=0.001, alpha=alpha,
max_iter=100000, random_state=42)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
lin_clf.fit(X_scaled, y)
svm_clf.fit(X_scaled, y)
sgd_clf.fit(X_scaled, y)
print("LinearSVC: ", lin_clf.intercept_, lin_clf.coef_)
print("SVC: ", svm_clf.intercept_, svm_clf.coef_)
print("SGDClassifier(alpha={:.5f}):".format(sgd_clf.alpha), sgd_clf.intercept_, sgd_clf.coef_)
# Compute the slope and bias of each decision boundary
w1 = -lin_clf.coef_[0, 0]/lin_clf.coef_[0, 1]
b1 = -lin_clf.intercept_[0]/lin_clf.coef_[0, 1]
w2 = -svm_clf.coef_[0, 0]/svm_clf.coef_[0, 1]
b2 = -svm_clf.intercept_[0]/svm_clf.coef_[0, 1]
w3 = -sgd_clf.coef_[0, 0]/sgd_clf.coef_[0, 1]
b3 = -sgd_clf.intercept_[0]/sgd_clf.coef_[0, 1]
# Transform the decision boundary lines back to the original scale
line1 = scaler.inverse_transform([[-10, -10 * w1 + b1], [10, 10 * w1 + b1]])
line2 = scaler.inverse_transform([[-10, -10 * w2 + b2], [10, 10 * w2 + b2]])
line3 = scaler.inverse_transform([[-10, -10 * w3 + b3], [10, 10 * w3 + b3]])
# Plot all three decision boundaries
plt.figure(figsize=(11, 4))
plt.plot(line1[:, 0], line1[:, 1], "k:", label="LinearSVC")
plt.plot(line2[:, 0], line2[:, 1], "b--", linewidth=2, label="SVC")
plt.plot(line3[:, 0], line3[:, 1], "r-", label="SGDClassifier")
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "bs") # label="Iris-Versicolor"
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "yo") # label="Iris-Setosa"
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
plt.legend(loc="upper center", fontsize=14)
plt.axis([0, 5.5, 0, 2])
plt.show()
The aim of the SVM algorithm is to find a hyperplane in a \( p \)-dimensional space, where \( p \) is the number of features that distinctly classifies the data points.
In a \( p \)-dimensional space, a hyperplane is what we call an affine subspace of dimension of \( p-1 \). As an example, in two dimension, a hyperplane is simply as straight line while in three dimensions it is a two-dimensional subspace, or stated simply, a plane.
In two dimensions, with the variables \( x_1 \) and \( x_2 \), the hyperplane is defined as $$ b+w_1x_1+w_2x_2=0, $$
where \( b \) is the intercept and \( w_1 \) and \( w_2 \) define the elements of a vector orthogonal to the line \( b+w_1x_1+w_2x_2=0 \). In two dimensions we define the vectors \( \boldsymbol{x} =[x1,x2] \) and \( \boldsymbol{w}=[w1,w2] \). We can then rewrite the above equation as $$ \boldsymbol{x}^T\boldsymbol{w}+b=0. $$
We limit ourselves to two classes of outputs \( y_i \) and assign these classes the values \( y_i = \pm 1 \). In a \( p \)-dimensional space of say \( p \) features we have a hyperplane defines as $$ b+wx_1+w_2x_2+\dots +w_px_p=0. $$ If we define a matrix \( \boldsymbol{X}=\left[\boldsymbol{x}_1,\boldsymbol{x}_2,\dots, \boldsymbol{x}_p\right] \) of dimension \( n\times p \), where \( n \) represents the observations for each feature and each vector \( x_i \) is a column vector of the matrix \( \boldsymbol{X} \), $$ \boldsymbol{x}_i = \begin{bmatrix} x_{i1} \\ x_{i2} \\ \dots \\ \dots \\ x_{ip} \end{bmatrix}. $$ If the above condition is not met for a given vector \( \boldsymbol{x}_i \) we have $$ b+w_1x_{i1}+w_2x_{i2}+\dots +w_px_{ip} >0, $$ if our output \( y_i=1 \). In this case we say that \( \boldsymbol{x}_i \) lies on one of the sides of the hyperplane and if $$ b+w_1x_{i1}+w_2x_{i2}+\dots +w_px_{ip} < 0, $$ for the class of observations \( y_i=-1 \), then \( \boldsymbol{x}_i \) lies on the other side.
Equivalently, for the two classes of observations we have $$ y_i\left(b+w_1x_{i1}+w_2x_{i2}+\dots +w_px_{ip}\right) > 0. $$
When we try to separate hyperplanes, if it exists, we can use it to construct a natural classifier: a test observation is assigned a given class depending on which side of the hyperplane it is located.
Let us try to develop our intuition about SVMs by limiting ourselves to a two-dimensional plane. To separate the two classes of data points, there are many possible lines (hyperplanes if you prefer a more strict naming) that could be chosen. Our objective is to find a plane that has the maximum margin, i.e the maximum distance between data points of both classes. Maximizing the margin distance provides some reinforcement so that future data points can be classified with more confidence.
What a linear classifier attempts to accomplish is to split the feature space into two half spaces by placing a hyperplane between the data points. This hyperplane will be our decision boundary. All points on one side of the plane will belong to class one and all points on the other side of the plane will belong to the second class two.
Unfortunately there are many ways in which we can place a hyperplane to divide the data. Below is an example of two candidate hyperplanes for our data sample.
Let us define the function $$ f(x) = \boldsymbol{w}^T\boldsymbol{x}+b = 0, $$ as the function that determines the line \( L \) that separates two classes (our two features), see the figure here.
Any point defined by \( \boldsymbol{x}_i \) and \( \boldsymbol{x}_2 \) on the line \( L \) will satisfy \( \boldsymbol{w}^T(\boldsymbol{x}_1-\boldsymbol{x}_2)=0 \).
The signed distance \( \delta \) from any point defined by a vector \( \boldsymbol{x} \) and a point \( \boldsymbol{x}_0 \) on the line \( L \) is then $$ \delta = \frac{1}{\vert\vert \boldsymbol{w}\vert\vert}(\boldsymbol{w}^T\boldsymbol{x}+b). $$
How do we find the parameter \( b \) and the vector \( \boldsymbol{w} \)? What we could do is to define a cost function which now contains the set of all misclassified points \( M \) and attempt to minimize this function $$ C(\boldsymbol{w},b) = -\sum_{i\in M} y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b). $$
We could now for example define all values \( y_i =1 \) as misclassified in case we have \( \boldsymbol{w}^T\boldsymbol{x}_i+b < 0 \) and the opposite if we have \( y_i=-1 \). Taking the derivatives gives us $$ \frac{\partial C}{\partial b} = -\sum_{i\in M} y_i, $$ and $$ \frac{\partial C}{\partial \boldsymbol{w}} = -\sum_{i\in M} y_ix_i. $$
We can now use the Newton-Raphson method or different variants of the gradient descent family (from plain gradient descent to various stochastic gradient descent approaches) to solve the equations $$ b \leftarrow b +\eta \frac{\partial C}{\partial b}, $$ and $$ \boldsymbol{w} \leftarrow \boldsymbol{w} +\eta \frac{\partial C}{\partial \boldsymbol{w}}, $$ where \( \eta \) is our by now well-known learning rate.
The equations we discussed above can be coded rather easily (the framework is similar to what we developed for logistic regression). We are going to set up a simple case with two classes only and we want to find a line which separates them the best possible way.
There are however problems with this approach, although it looks pretty straightforward to implement. When running the above code, we see that we can easily end up with many diffeent lines which separate the two classes.
For small gaps between the entries, we may also end up needing many iterations before the solutions converge and if the data cannot be separated properly into two distinct classes, we may not experience a converge at all.
A better approach is rather to try to define a large margin between the two classes (if they are well separated from the beginning).
Thus, we wish to find a margin \( M \) with \( \boldsymbol{w} \) normalized to \( \vert\vert \boldsymbol{w}\vert\vert =1 \) subject to the condition $$ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) \geq M \hspace{0.1cm}\forall i=1,2,\dots, p. $$ All points are thus at a signed distance from the decision boundary defined by the line \( L \). The parameters \( b \) and \( w_1 \) and \( w_2 \) define this line.
We seek thus the largest value \( M \) defined by $$ \frac{1}{\vert \vert \boldsymbol{w}\vert\vert}y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) \geq M \hspace{0.1cm}\forall i=1,2,\dots, n, $$ or just $$ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) \geq M\vert \vert \boldsymbol{w}\vert\vert \hspace{0.1cm}\forall i. $$ If we scale the equation so that \( \vert \vert \boldsymbol{w}\vert\vert = 1/M \), we have to find the minimum of \( \boldsymbol{w}^T\boldsymbol{w}=\vert \vert \boldsymbol{w}\vert\vert \) (the norm) subject to the condition $$ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) \geq 1 \hspace{0.1cm}\forall i. $$
We have thus defined our margin as the invers of the norm of \( \boldsymbol{w} \). We want to minimize the norm in order to have a as large as possible margin \( M \). Before we proceed, we need to remind ourselves about Lagrangian multipliers.
Consider a function of three independent variables \( f(x,y,z) \) . For the function \( f \) to be an extreme we have $$ df=0. $$ A necessary and sufficient condition is $$ \frac{\partial f}{\partial x} =\frac{\partial f}{\partial y}=\frac{\partial f}{\partial z}=0, $$ due to $$ df = \frac{\partial f}{\partial x}dx+\frac{\partial f}{\partial y}dy+\frac{\partial f}{\partial z}dz. $$ In many problems the variables \( x,y,z \) are often subject to constraints (such as those above for the margin) so that they are no longer all independent. It is possible at least in principle to use each constraint to eliminate one variable and to proceed with a new and smaller set of independent varables.
The use of so-called Lagrangian multipliers is an alternative technique when the elimination of variables is incovenient or undesirable. Assume that we have an equation of constraint on the variables \( x,y,z \) $$ \phi(x,y,z) = 0, $$ resulting in $$ d\phi = \frac{\partial \phi}{\partial x}dx+\frac{\partial \phi}{\partial y}dy+\frac{\partial \phi}{\partial z}dz =0. $$ Now we cannot set anymore $$ \frac{\partial f}{\partial x} =\frac{\partial f}{\partial y}=\frac{\partial f}{\partial z}=0, $$ if \( df=0 \) is wanted because there are now only two independent variables! Assume \( x \) and \( y \) are the independent variables. Then \( dz \) is no longer arbitrary.
However, we can add to $$ df = \frac{\partial f}{\partial x}dx+\frac{\partial f}{\partial y}dy+\frac{\partial f}{\partial z}dz, $$ a multiplum of \( d\phi \), viz. \( \lambda d\phi \), resulting in $$ df+\lambda d\phi = (\frac{\partial f}{\partial z}+\lambda \frac{\partial \phi}{\partial x})dx+(\frac{\partial f}{\partial y}+\lambda\frac{\partial \phi}{\partial y})dy+ (\frac{\partial f}{\partial z}+\lambda\frac{\partial \phi}{\partial z})dz =0. $$ Our multiplier is chosen so that $$ \frac{\partial f}{\partial z}+\lambda\frac{\partial \phi}{\partial z} =0. $$
We need to remember that we took \( dx \) and \( dy \) to be arbitrary and thus we must have $$ \frac{\partial f}{\partial x}+\lambda\frac{\partial \phi}{\partial x} =0, $$ and $$ \frac{\partial f}{\partial y}+\lambda\frac{\partial \phi}{\partial y} =0. $$ When all these equations are satisfied, \( df=0 \). We have four unknowns, \( x,y,z \) and \( \lambda \). Actually we want only \( x,y,z \), \( \lambda \) needs not to be determined, it is therefore often called Lagrange's undetermined multiplier. If we have a set of constraints \( \phi_k \) we have the equations $$ \frac{\partial f}{\partial x_i}+\sum_k\lambda_k\frac{\partial \phi_k}{\partial x_i} =0. $$
Taking the derivatives with respect to \( b \) and \( \boldsymbol{w} \) we obtain $$ \frac{\partial {\cal L}}{\partial b} = -\sum_{i} \lambda_iy_i=0, $$ and $$ \frac{\partial {\cal L}}{\partial \boldsymbol{w}} = 0 = \boldsymbol{w}-\sum_{i} \lambda_iy_i\boldsymbol{x}_i. $$ Inserting these constraints into the equation for \( {\cal L} \) we obtain $$ {\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{x}_i^T\boldsymbol{x}_j, $$ subject to the constraints \( \lambda_i\geq 0 \) and \( \sum_i\lambda_iy_i=0 \). We must in addition satisfy the Karush-Kuhn-Tucker (KKT) condition $$ \lambda_i\left[y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) -1\right] \hspace{0.1cm}\forall i. $$
We can rewrite $$ {\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{x}_i^T\boldsymbol{x}_j, $$ and its constraints in terms of a matrix-vector problem where we minimize w.r.t. \( \lambda \) the following problem $$ \frac{1}{2} \boldsymbol{\lambda}^T\begin{bmatrix} y_1y_1\boldsymbol{x}_1^T\boldsymbol{x}_1 & y_1y_2\boldsymbol{x}_1^T\boldsymbol{x}_2 & \dots & \dots & y_1y_n\boldsymbol{x}_1^T\boldsymbol{x}_n \\ y_2y_1\boldsymbol{x}_2^T\boldsymbol{x}_1 & y_2y_2\boldsymbol{x}_2^T\boldsymbol{x}_2 & \dots & \dots & y_1y_n\boldsymbol{x}_2^T\boldsymbol{x}_n \\ \dots & \dots & \dots & \dots & \dots \\ \dots & \dots & \dots & \dots & \dots \\ y_ny_1\boldsymbol{x}_n^T\boldsymbol{x}_1 & y_ny_2\boldsymbol{x}_n^T\boldsymbol{x}_2 & \dots & \dots & y_ny_n\boldsymbol{x}_n^T\boldsymbol{x}_n \\ \end{bmatrix}\boldsymbol{\lambda}-\mathbb{1}\boldsymbol{\lambda}, $$ subject to \( \boldsymbol{y}^T\boldsymbol{\lambda}=0 \). Here we defined the vectors \( \boldsymbol{\lambda} =[\lambda_1,\lambda_2,\dots,\lambda_n] \) and \( \boldsymbol{y}=[y_1,y_2,\dots,y_n] \).
Solving the above problem, yields the values of \( \lambda_i \). To find the coefficients of your hyperplane we need simply to compute $$ \boldsymbol{w}=\sum_{i} \lambda_iy_i\boldsymbol{x}_i. $$ With our vector \( \boldsymbol{w} \) we can in turn find the value of the intercept \( b \) (here in two dimensions) via $$ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1, $$ resulting in $$ b = \frac{1}{y_i}-\boldsymbol{w}^T\boldsymbol{x}_i, $$ or if we write it out in terms of the support vectors only, with \( N_s \) being their number, we have $$ b = \frac{1}{N_s}\sum_{j\in N_s}\left(y_j-\sum_{i=1}^n\lambda_iy_i\boldsymbol{x}_i^T\boldsymbol{x}_j\right). $$ With our hyperplane coefficients we can use our classifier to assign any observation by simply using $$ y_i = \mathrm{sign}(\boldsymbol{w}^T\boldsymbol{x}_i+b). $$ Below we discuss how to find the optimal values of \( \lambda_i \). Before we proceed however, we discuss now the so-called soft classifier.
Till now, the margin is strictly defined by the support vectors. This defines what is called a hard classifier, that is the margins are well defined.
Suppose now that classes overlap in feature space, as shown in the figure here. One way to deal with this problem before we define the so-called kernel approach, is to allow a kind of slack in the sense that we allow some points to be on the wrong side of the margin.
We introduce thus the so-called slack variables \( \boldsymbol{\xi} =[\xi_1,x_2,\dots,x_n] \) and modify our previous equation $$ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1, $$ to $$ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1-\xi_i, $$ with the requirement \( \xi_i\geq 0 \). The total violation is now \( \sum_i\xi \). The value \( \xi_i \) in the constraint the last constraint corresponds to the amount by which the prediction \( y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1 \) is on the wrong side of its margin. Hence by bounding the sum \( \sum_i \xi_i \), we bound the total amount by which predictions fall on the wrong side of their margins.
Misclassifications occur when \( \xi_i > 1 \). Thus bounding the total sum by some value \( C \) bounds in turn the total number of misclassifications.
This has in turn the consequences that we change our optmization problem to finding the minimum of $$ {\cal L}=\frac{1}{2}\boldsymbol{w}^T\boldsymbol{w}-\sum_{i=1}^n\lambda_i\left[y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)-(1-\xi_)\right]+C\sum_{i=1}^n\xi_i-\sum_{i=1}^n\gamma_i\xi_i, $$ subject to $$ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1-\xi_i \hspace{0.1cm}\forall i, $$ with the requirement \( \xi_i\geq 0 \).
Taking the derivatives with respect to \( b \) and \( \boldsymbol{w} \) we obtain $$ \frac{\partial {\cal L}}{\partial b} = -\sum_{i} \lambda_iy_i=0, $$ and $$ \frac{\partial {\cal L}}{\partial \boldsymbol{w}} = 0 = \boldsymbol{w}-\sum_{i} \lambda_iy_i\boldsymbol{x}_i, $$ and $$ \lambda_i = C-\gamma_i \hspace{0.1cm}\forall i. $$ Inserting these constraints into the equation for \( {\cal L} \) we obtain the same equation as before $$ {\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{x}_i^T\boldsymbol{x}_j, $$ but now subject to the constraints \( \lambda_i\geq 0 \), \( \sum_i\lambda_iy_i=0 \) and \( 0\leq\lambda_i \leq C \). We must in addition satisfy the Karush-Kuhn-Tucker condition which now reads $$ \lambda_i\left[y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) -(1-\xi_)\right]=0 \hspace{0.1cm}\forall i, $$ $$ \gamma_i\xi_i = 0, $$ and $$ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) -(1-\xi_) \geq 0 \hspace{0.1cm}\forall i. $$
The cases we have studied till now, were all characterized by two classes with a close to linear separability. The classifiers we have described so far find linear boundaries in our input feature space. It is possible to make our procedure more flexible by exploring the feature space using other basis expansions such as higher-order polynomials, wavelets, splines etc.
If our feature space is not easy to separate, as shown in the figure here, we can achieve a better separation by introducing more complex basis functions. The ideal would be, as shown in the next figure, to, via a specific transformation to obtain a separation between the classes which is almost linear.
The change of basis, from \( x\rightarrow z=\phi(x) \) leads to the same type of equations to be solved, except that we need to introduce for example a polynomial transformation to a two-dimensional training set.
import numpy as np
import os
np.random.seed(42)
# To plot pretty figures
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
from sklearn.svm import SVC
from sklearn import datasets
X1D = np.linspace(-4, 4, 9).reshape(-1, 1)
X2D = np.c_[X1D, X1D**2]
y = np.array([0, 0, 1, 1, 1, 1, 1, 0, 0])
plt.figure(figsize=(11, 4))
plt.subplot(121)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.plot(X1D[:, 0][y==0], np.zeros(4), "bs")
plt.plot(X1D[:, 0][y==1], np.zeros(5), "g^")
plt.gca().get_yaxis().set_ticks([])
plt.xlabel(r"$x_1$", fontsize=20)
plt.axis([-4.5, 4.5, -0.2, 0.2])
plt.subplot(122)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.plot(X2D[:, 0][y==0], X2D[:, 1][y==0], "bs")
plt.plot(X2D[:, 0][y==1], X2D[:, 1][y==1], "g^")
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"$x_2$", fontsize=20, rotation=0)
plt.gca().get_yaxis().set_ticks([0, 4, 8, 12, 16])
plt.plot([-4.5, 4.5], [6.5, 6.5], "r--", linewidth=3)
plt.axis([-4.5, 4.5, -1, 17])
plt.subplots_adjust(right=1)
plt.show()
Suppose we define a polynomial transformation of degree two only (we continue to live in a plane with \( x_i \) and \( y_i \) as variables) $$ z = \phi(x_i) =\left(x_i^2, y_i^2, \sqrt{2}x_iy_i\right). $$
With our new basis, the equations we solved earlier are basically the same, that is we have now (without the slack option for simplicity) $$ {\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{z}_i^T\boldsymbol{z}_j, $$ subject to the constraints \( \lambda_i\geq 0 \), \( \sum_i\lambda_iy_i=0 \), and for the support vectors $$ y_i(\boldsymbol{w}^T\boldsymbol{z}_i+b)= 1 \hspace{0.1cm}\forall i, $$ from which we also find \( b \). To compute \( \boldsymbol{z}_i^T\boldsymbol{z}_j \) we define the kernel \( K(\boldsymbol{x}_i,\boldsymbol{x}_j) \) as $$ K(\boldsymbol{x}_i,\boldsymbol{x}_j)=\boldsymbol{z}_i^T\boldsymbol{z}_j= \phi(\boldsymbol{x}_i)^T\phi(\boldsymbol{x}_j). $$ For the above example, the kernel reads $$ K(\boldsymbol{x}_i,\boldsymbol{x}_j)=[x_i^2, y_i^2, \sqrt{2}x_iy_i]^T\begin{bmatrix} x_j^2 \\ y_j^2 \\ \sqrt{2}x_jy_j \end{bmatrix}=x_i^2x_j^2+2x_ix_jy_iy_j+y_i^2y_j^2. $$
We note that this is nothing but the dot product of the two original vectors \( (\boldsymbol{x}_i^T\boldsymbol{x}_j)^2 \). Instead of thus computing the product in the Lagrangian of \( \boldsymbol{z}_i^T\boldsymbol{z}_j \) we simply compute the dot product \( (\boldsymbol{x}_i^T\boldsymbol{x}_j)^2 \).
This leads to the so-called kernel trick and the result leads to the same as if we went through the trouble of performing the transformation \( \phi(\boldsymbol{x}_i)^T\phi(\boldsymbol{x}_j) \) during the SVM calculations.
We can rewrite this (see the solutions below) in terms of a convex optimization problem of the type $$ \begin{align*} &\mathrm{min}_{\lambda}\hspace{0.2cm} \frac{1}{2}\boldsymbol{\lambda}^T\boldsymbol{P}\boldsymbol{\lambda}+\boldsymbol{q}^T\boldsymbol{\lambda},\\ \nonumber &\mathrm{subject\hspace{0.1cm}to} \hspace{0.2cm} \boldsymbol{G}\boldsymbol{\lambda} \preceq \boldsymbol{h} \hspace{0.2cm} \wedge \boldsymbol{A}\boldsymbol{\lambda}=f. \end{align*} $$ Below we discuss how to solve these equations. Here we note that the matrix \( \boldsymbol{P} \) has matrix elements \( p_{ij}=y_iy_jK(\boldsymbol{x}_i,\boldsymbol{x}_j) \). Given a kernel \( K \) and the targets \( y_i \) this matrix is easy to set up. The constraint \( \boldsymbol{y}^T\boldsymbol{\lambda}=0 \) leads to \( f=0 \) and \( \boldsymbol{A}=\boldsymbol{y} \). How to set up the matrix \( \boldsymbol{G} \) is discussed later. Here note that the inequalities \( 0\leq \lambda_i \leq C \) can be split up into \( 0\leq \lambda_i \) and \( \lambda_i \leq C \). These two inequalities define then the matrix \( \boldsymbol{G} \) and the vector \( \boldsymbol{h} \).
There are several popular kernels being used. These are
An important theorem for us is Mercer's theorem. The theorem states that if a kernel function \( K \) is symmetric, continuous and leads to a positive semi-definite matrix \( \boldsymbol{P} \) then there exists a function \( \phi \) that maps \( \boldsymbol{x}_i \) and \( \boldsymbol{x}_j \) into another space (possibly with much higher dimensions) such that $$ K(\boldsymbol{x}_i,\boldsymbol{x}_j)=\phi(\boldsymbol{x}_i)^T\phi(\boldsymbol{x}_j). $$
So you can use \( K \) as a kernel since you know \( \phi \) exists, even if you don’t know what \( \phi \) is.
Note that some frequently used kernels (such as the Sigmoid kernel) don’t respect all of Mercer’s conditions, yet they generally work well in practice.
from __future__ import division, print_function, unicode_literals
import numpy as np
np.random.seed(42)
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
from sklearn.svm import SVC
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
from sklearn.datasets import make_moons
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)
def plot_dataset(X, y, axes):
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "bs")
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")
plt.axis(axes)
plt.grid(True, which='both')
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"$x_2$", fontsize=20, rotation=0)
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.show()
from sklearn.datasets import make_moons
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
polynomial_svm_clf = Pipeline([
("poly_features", PolynomialFeatures(degree=3)),
("scaler", StandardScaler()),
("svm_clf", LinearSVC(C=10, loss="hinge", random_state=42))
])
polynomial_svm_clf.fit(X, y)
def plot_predictions(clf, axes):
x0s = np.linspace(axes[0], axes[1], 100)
x1s = np.linspace(axes[2], axes[3], 100)
x0, x1 = np.meshgrid(x0s, x1s)
X = np.c_[x0.ravel(), x1.ravel()]
y_pred = clf.predict(X).reshape(x0.shape)
y_decision = clf.decision_function(X).reshape(x0.shape)
plt.contourf(x0, x1, y_pred, cmap=plt.cm.brg, alpha=0.2)
plt.contourf(x0, x1, y_decision, cmap=plt.cm.brg, alpha=0.1)
plot_predictions(polynomial_svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.show()
from sklearn.svm import SVC
poly_kernel_svm_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="poly", degree=3, coef0=1, C=5))
])
poly_kernel_svm_clf.fit(X, y)
poly100_kernel_svm_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="poly", degree=10, coef0=100, C=5))
])
poly100_kernel_svm_clf.fit(X, y)
plt.figure(figsize=(11, 4))
plt.subplot(121)
plot_predictions(poly_kernel_svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.title(r"$d=3, r=1, C=5$", fontsize=18)
plt.subplot(122)
plot_predictions(poly100_kernel_svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.title(r"$d=10, r=100, C=5$", fontsize=18)
plt.show()
def gaussian_rbf(x, landmark, gamma):
return np.exp(-gamma * np.linalg.norm(x - landmark, axis=1)**2)
gamma = 0.3
x1s = np.linspace(-4.5, 4.5, 200).reshape(-1, 1)
x2s = gaussian_rbf(x1s, -2, gamma)
x3s = gaussian_rbf(x1s, 1, gamma)
XK = np.c_[gaussian_rbf(X1D, -2, gamma), gaussian_rbf(X1D, 1, gamma)]
yk = np.array([0, 0, 1, 1, 1, 1, 1, 0, 0])
plt.figure(figsize=(11, 4))
plt.subplot(121)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.scatter(x=[-2, 1], y=[0, 0], s=150, alpha=0.5, c="red")
plt.plot(X1D[:, 0][yk==0], np.zeros(4), "bs")
plt.plot(X1D[:, 0][yk==1], np.zeros(5), "g^")
plt.plot(x1s, x2s, "g--")
plt.plot(x1s, x3s, "b:")
plt.gca().get_yaxis().set_ticks([0, 0.25, 0.5, 0.75, 1])
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"Similarity", fontsize=14)
plt.annotate(r'$\mathbf{x}$',
xy=(X1D[3, 0], 0),
xytext=(-0.5, 0.20),
ha="center",
arrowprops=dict(facecolor='black', shrink=0.1),
fontsize=18,
)
plt.text(-2, 0.9, "$x_2$", ha="center", fontsize=20)
plt.text(1, 0.9, "$x_3$", ha="center", fontsize=20)
plt.axis([-4.5, 4.5, -0.1, 1.1])
plt.subplot(122)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.plot(XK[:, 0][yk==0], XK[:, 1][yk==0], "bs")
plt.plot(XK[:, 0][yk==1], XK[:, 1][yk==1], "g^")
plt.xlabel(r"$x_2$", fontsize=20)
plt.ylabel(r"$x_3$ ", fontsize=20, rotation=0)
plt.annotate(r'$\phi\left(\mathbf{x}\right)$',
xy=(XK[3, 0], XK[3, 1]),
xytext=(0.65, 0.50),
ha="center",
arrowprops=dict(facecolor='black', shrink=0.1),
fontsize=18,
)
plt.plot([-0.1, 1.1], [0.57, -0.1], "r--", linewidth=3)
plt.axis([-0.1, 1.1, -0.1, 1.1])
plt.subplots_adjust(right=1)
plt.show()
x1_example = X1D[3, 0]
for landmark in (-2, 1):
k = gaussian_rbf(np.array([[x1_example]]), np.array([[landmark]]), gamma)
print("Phi({}, {}) = {}".format(x1_example, landmark, k))
rbf_kernel_svm_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="rbf", gamma=5, C=0.001))
])
rbf_kernel_svm_clf.fit(X, y)
from sklearn.svm import SVC
gamma1, gamma2 = 0.1, 5
C1, C2 = 0.001, 1000
hyperparams = (gamma1, C1), (gamma1, C2), (gamma2, C1), (gamma2, C2)
svm_clfs = []
for gamma, C in hyperparams:
rbf_kernel_svm_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="rbf", gamma=gamma, C=C))
])
rbf_kernel_svm_clf.fit(X, y)
svm_clfs.append(rbf_kernel_svm_clf)
plt.figure(figsize=(11, 7))
for i, svm_clf in enumerate(svm_clfs):
plt.subplot(221 + i)
plot_predictions(svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
gamma, C = hyperparams[i]
plt.title(r"$\gamma = {}, C = {}$".format(gamma, C), fontsize=16)
plt.show()
A mathematical (quadratic) optimization problem, or just optimization problem, has the form $$ \begin{align*} &\mathrm{min}_{\lambda}\hspace{0.2cm} \frac{1}{2}\boldsymbol{\lambda}^T\boldsymbol{P}\boldsymbol{\lambda}+\boldsymbol{q}^T\boldsymbol{\lambda},\\ \nonumber &\mathrm{subject\hspace{0.1cm}to} \hspace{0.2cm} \boldsymbol{G}\boldsymbol{\lambda} \preceq \boldsymbol{h} \wedge \boldsymbol{A}\boldsymbol{\lambda}=f. \end{align*} $$ subject to some constraints for say a selected set \( i=1,2,\dots, n \). In our case we are optimizing with respect to the Lagrangian multipliers \( \lambda_i \), and the vector \( \boldsymbol{\lambda}=[\lambda_1, \lambda_2,\dots, \lambda_n] \) is the optimization variable we are dealing with.
In our case we are particularly interested in a class of optimization problems called convex optmization problems. In our discussion on gradient descent methods we discussed at length the definition of a convex function.
Convex optimization problems play a central role in applied mathematics and we recommend strongly Boyd and Vandenberghe's text on the topics.
If we use Python as programming language and wish to venture beyond scikit-learn, tensorflow and similar software which makes our lives so much easier, we need to dive into the wonderful world of quadratic programming. We can, if we wish, solve the minimization problem using say standard gradient methods or conjugate gradient methods. However, these methods tend to exhibit a rather slow converge. So, welcome to the promised land of quadratic programming.
The functions we need are contained in the quadratic programming package CVXOPT and we need to import it together with numpy as
import numpy
import cvxopt
This will make our life much easier. You don't need t write your own optimizer.
We remind ourselves about the general problem we want to solve $$ \begin{align*} &\mathrm{min}_{x}\hspace{0.2cm} \frac{1}{2}\boldsymbol{x}^T\boldsymbol{P}\boldsymbol{x}+\boldsymbol{q}^T\boldsymbol{x},\\ \nonumber &\mathrm{subject\hspace{0.1cm} to} \hspace{0.2cm} \boldsymbol{G}\boldsymbol{x} \preceq \boldsymbol{h} \wedge \boldsymbol{A}\boldsymbol{x}=f. \end{align*} $$
Let us show how to perform the optmization using a simple case. Assume we want to optimize the following problem $$ \begin{align*} &\mathrm{min}_{x}\hspace{0.2cm} \frac{1}{2}x^2+5x+3y \\ \nonumber &\mathrm{subject to} \\ \nonumber &x, y \geq 0 \\ \nonumber &x+3y \geq 15 \\ \nonumber &2x+5y \leq 100 \\ \nonumber &3x+4y \leq 80. \\ \nonumber \end{align*} $$ The minimization problem can be rewritten in terms of vectors and matrices as (with \( x \) and \( y \) being the unknowns) $$ \frac{1}{2}\begin{bmatrix} x\\ y \end{bmatrix}^T \begin{bmatrix} 1 & 0\\ 0 & 0 \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix}3\\ 4 \end{bmatrix}^T \begin{bmatrix}x \\ y \end{bmatrix}. $$ Similarly, we can now set up the inequalities (we need to change \( \geq \) to \( \leq \) by multiplying with \( -1 \) on bot sides) as the following matrix-vector equation $$ \begin{bmatrix} -1 & 0 \\ 0 & -1 \\ -1 & -3 \\ 2 & 5 \\ 3 & 4\end{bmatrix}\begin{bmatrix} x \\ y\end{bmatrix} \preceq \begin{bmatrix}0 \\ 0\\ -15 \\ 100 \\ 80\end{bmatrix}. $$ We have collapsed all the inequalities into a single matrix \( \boldsymbol{G} \). We see also that our matrix $$ \boldsymbol{P} =\begin{bmatrix} 1 & 0\\ 0 & 0 \end{bmatrix} $$ is clearly positive semi-definite (all eigenvalues larger or equal zero). Finally, the vector \( \boldsymbol{h} \) is defined as $$ \boldsymbol{h} = \begin{bmatrix}0 \\ 0\\ -15 \\ 100 \\ 80\end{bmatrix}. $$
Since we don't have any equalities the matrix \( \boldsymbol{A} \) is set to zero The following code solves the equations for us
# Import the necessary packages
import numpy
from cvxopt import matrix
from cvxopt import solvers
P = matrix(numpy.diag([1,0]), tc=’d’)
q = matrix(numpy.array([3,4]), tc=’d’)
G = matrix(numpy.array([[-1,0],[0,-1],[-1,-3],[2,5],[3,4]]), tc=’d’)
h = matrix(numpy.array([0,0,-15,100,80]), tc=’d’)
# Construct the QP, invoke solver
sol = solvers.qp(P,q,G,h)
# Extract optimal value and solution
sol[’x’]
sol[’primal objective’]
We are now ready to return to our setup of the optmization problem for a more realistic case. Introducing the slack parameter \( C \) we have $$ \frac{1}{2} \boldsymbol{\lambda}^T\begin{bmatrix} y_1y_1K(\boldsymbol{x}_1,\boldsymbol{x}_1) & y_1y_2K(\boldsymbol{x}_1,\boldsymbol{x}_2) & \dots & \dots & y_1y_nK(\boldsymbol{x}_1,\boldsymbol{x}_n) \\ y_2y_1K(\boldsymbol{x}_2,\boldsymbol{x}_1) & y_2y_2K(\boldsymbol{x}_2,\boldsymbol{x}_2) & \dots & \dots & y_1y_nK(\boldsymbol{x}_2,\boldsymbol{x}_n) \\ \dots & \dots & \dots & \dots & \dots \\ \dots & \dots & \dots & \dots & \dots \\ y_ny_1K(\boldsymbol{x}_n,\boldsymbol{x}_1) & y_ny_2K(\boldsymbol{x}_n\boldsymbol{x}_2) & \dots & \dots & y_ny_nK(\boldsymbol{x}_n,\boldsymbol{x}_n) \\ \end{bmatrix}\boldsymbol{\lambda}-\mathbb{I}\boldsymbol{\lambda}, $$ subject to \( \boldsymbol{y}^T\boldsymbol{\lambda}=0 \). Here we defined the vectors \( \boldsymbol{\lambda} =[\lambda_1,\lambda_2,\dots,\lambda_n] \) and \( \boldsymbol{y}=[y_1,y_2,\dots,y_n] \). With the slack constants this leads to the additional constraint \( 0\leq \lambda_i \leq C \).
code will be added


I bought three grams of wormwood resin extract (10X) off a website based out of the Netherlands. It came as several chunks that looked like solid mud, but was much harder to break up. I crushed it into an orange-brown crystalline powder which reminded me of topaz flakes. It had the slight smell of pine needles. I put a tiny nugget of marijuana in the bottom of a glass pipe to prevent the powder from falling through, and added the wormwood on top. In total the pile of powder was about the size of a dime around and about half a centimeter high.  I was very comfortable and had little to no anxiety over trying the extract.
The smoke was unusually hot and it had a rather unpleasant, plastic-like taste. The crystals sizzled a bit at first when lit, and they fused together into a solid mass after each toke which had to be broken up with a knife tip. As with any smoke, the effects were rather immediate. At lower doses, it was very similar to marijuana, with generalized feelings of sedation and contentment, but my limbs felt heavier. Other similarities include turning down the volume knob on conscious thought, and that 'buzzed' or lightheaded feeling.
I got into a meditational posture, and I found it easy to keep the correct mindstate without attention to breath or other techniques. As I continued to smoke (which took several minutes due to the rather harsh nature of the smoke itself), the differences from cannabis became clearer. Wormwood did not have the effect of diminishing short-term memory. My muscles became rather tense and mildly sore, making me want to stretch. There was a mild tension in my chest, and my throat felt a little tight, but both were fully ignorable. Unlike marijuana which gives me a certain cheeriness, I felt blankly content.
Visuals were nearly absent, but there was some interplay between light and shadow and a few vague yellow and blue overlays on objects, likened to what you see for a second after you close your eyes, but with eyes still open-- psychologists call this 'negative after images'. While in the meditational mindstate, it seemed like whatever I focussed on became stronger, and the rest simply faded out of awareness. I felt quite unmotivated too.
There was only one effect which I found significant. After five or so minutes of taking these small, harsh hits, the crystals had turned black, and I stopped trying to get more out of it. Around that time, the 'buzzed' feeling slowly expanded outwards. A pressure began to build in my head, pushing out mainly forward but also up slightly. It was focussed around my forehead, the strongest sensation coming from the area of the third eye. It was truly an odd feeling, for it gave me the impression of sensing or feeling the area directly in front of my head. This, the peak, lasted for fifteen minutes or so. The effects slowly subsided, and were gone in about two hours.
I have since given it to several other experienced trippers, and most simply liken it to marijuana, only a little different. For me, it felt like a rather superficial drug with the strange coincidence of giving a specific sensation in the third eye region. After a half dozen experiences, I feel no need to order any more (although I would try pure thujone if given the opportunity). Overall I would say that it's worth a try, but do not expect to get anything profound or meaningful out of it. It's like marijuana, but inferior to it in my opinion.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


# -*- coding: utf-8 -*-
"""
This module contains functionality for transporting
log messages over the network.
"""
from typing import Any, Union, Optional, Callable, Sequence, Iterable
from zmq import Context, Poller, \
PUB, SUB, PUSH, PULL, SUBSCRIBE, NOBLOCK, POLLIN
from .signals import is_stopped
_TOPIC_ENCODING = 'UTF-8'
_LINE_ENCODING = 'UTF-8'
def _multipart_message(topic: str, line: str):
return [
topic.encode(encoding=_TOPIC_ENCODING, errors='ignore'),
line.encode(encoding=_LINE_ENCODING, errors='ignore')
]
[docs]class Broadcaster(object):
"""
A text line broadcaster.
:param bind_address:
An IP and port to bind the ZeroMQ socket to.
E.g. ``<IP_ADDRESS>:9001``
:type bind_address: str
:param ctx:
An existing ZeroMQ context to use for the IO work.
If `None` uses the default singleton instance.
:type ctx: Optional[zmq.Context]
"""
def __init__(self, bind_address: str,
ctx: Optional[Context] = None):
self._ctx = ctx or Context.instance()
self._socket = self._ctx.socket(PUB)
self._socket.bind('tcp://' + bind_address)
def __enter__(self):
return self
def __exit__(self):
self.close()
[docs] def send(self, topic: str, line: str):
"""
Broadcasts the given text line.
:param topic:
The topic association of the text line.
:type topic: str
:param line:
The text line.
:type line: str
"""
data = _multipart_message(topic, line.rstrip('\n\r'))
self._socket.send_multipart(data)
[docs] def send_raw(self, data: Sequence[bytes]):
"""
Broadcasts a raw multipart message.
:param data:
A raw multipart message.
:type data: Sequence[bytes]
"""
self._socket.send_multipart(data)
[docs] def close(self):
"""
Closes the ZeroMQ socket and releases allocated resources.
"""
self._socket.close()
self._socket = None
self._ctx = None
[docs]class Transmitter(object):
"""
A text line transmitter.
:param connect_addresses:
An iterable with addresses to connect the ZeroMQ PUSH socket to.
E.g. ``["log-proxy-1.my-company.com:9001", "<IP_ADDRESS>:9001"]``
:type connect_addresses: Iterable[str]
:param ctx:
An existing ZeroMQ context to use for the IO work.
If `None` uses the default singleton instance.
:type ctx: Optional[zmq.Context]
"""
def __init__(self,
connect_addresses: Iterable[str],
ctx: Optional[Context] = None):
self._ctx = ctx or Context.instance()
self._socket = self._ctx.socket(PUSH)
for address in connect_addresses:
self._socket.connect('tcp://' + address)
def __enter__(self):
return self
def __exit__(self):
self.close()
[docs] def send(self, topic: str, line: str):
"""
Transmits the given text line.
:param topic:
The topic association of the text line.
:type topic: str
:param line:
The text line.
:type line: str
"""
data = _multipart_message(topic, line.rstrip('\n\r'))
self._socket.send_multipart(data)
[docs] def send_raw(self, data: Sequence[bytes]):
"""
Transmits a raw multipart message.
:param data:
A raw multipart message.
:type data: Sequence[bytes]
"""
self._socket.send_multipart(data)
[docs] def close(self):
"""
Closes the ZeroMQ socket and releases allocated resources.
"""
self._socket.close()
self._socket = None
self._ctx = None
[docs]class Listener(object):
"""
Subscribes to one or more ZeroMQ PUB sockets,
and/or waits for connections from ZeroMQ PUSH sockets;
passing received log messages to a callback.
:param handler:
A function which is called every time a log message is received;
this is called with `source`, `filename`, and `line` arguments.
Alternatively an object with a method
``notify_line(source, filename, line)``
and optionally the methods ``notify_watch(source, filename)`` and
``notify_unwatch(source, filename)``.
:type handler: Optional[Union[Callable[[str, str, str], None], Any]]
:param watch_cb:
A function which is called every time a file has joined the
set of watched files;
this is called with a `filename` argument.
:type watch_cb: Optional[Callable[[str, str], None]]
:param unwatch_cb:
A function which is called every time a file has left the
set of watched files;
this is called with a `filename` argument.
:type unwatch_cb: Optional[Callable[[str, str], None]]
:param raw_cb:
A function which is called on every received message.
This is called with a sequence of `bytes`; the raw multi-message.
:type raw_cb: Optional[Callable[[Sequence[bytes]], None]]
:param bind_address:
An IP and port to bind the ZeroMQ PULL socket to.
E.g. ``<IP_ADDRESS>:9000``.
:type bind_address: Optional[str]
:param connect_addresses:
An iterable of addresses to connect the ZeroMQ SUB socket to.
E.g. ``["log-proxy-1.my-company.com:9001", "<IP_ADDRESS>:9001"]``
:type connect_addresses: Optional[Iterable[str]]
:param interval:
The timeout in seconds when waiting for new messages
before handling possible interruption.
:type interval: float
:param ctx:
An existing ZeroMQ context to use for the IO work.
If `None` uses the default singleton instance.
:type ctx: Optional[zmq.Context]
"""
def __init__(self,
handler: Optional[Union[Callable[[str, str, str], None], Any]] = None,
watch_cb: Optional[Callable[[str, str], None]] = None,
unwatch_cb: Optional[Callable[[str, str], None]] = None,
raw_cb: Optional[Callable[[Sequence[bytes]], None]] = None,
bind_address: Optional[str] = None,
connect_addresses: Optional[Iterable[str]] = None,
interval: float = 0.1,
ctx: Optional[Context] = None):
self._bind_address = bind_address
self._connect_addresses = list(connect_addresses)
if handler \
and hasattr(handler, 'notify_line') \
and callable(getattr(handler, 'notify_line')):
# treat handler as an object with notify_* methods
self._line_cb = handler.notify_line
self._watch = getattr(handler, 'notify_watch', watch_cb)
self._unwatch = getattr(handler, 'notify_unwatch', unwatch_cb)
else:
# otherwise treat it as the handler function for lines
self._line_cb = handler
self._watch_cb = watch_cb
self._unwatch_cb = unwatch_cb
self._raw_cb = raw_cb
self._interval = interval
self._ctx = ctx or Context.instance()
self._sub_socket = None
self._pull_socket = None
def _handle_message(self, data):
if self._raw_cb:
self._raw_cb(data)
if self._line_cb is None \
and self._watch_cb is None \
and self._unwatch_cb is None:
return
topic = data[0].decode(encoding=_TOPIC_ENCODING).split('|')
msg_type = topic[1]
if msg_type == 'line':
source_name = topic[2]
file_name = topic[3]
text = data[1].decode(encoding=_LINE_ENCODING)
if callable(self._line_cb):
self._line_cb(source_name, file_name, text)
elif msg_type == 'watch':
source_name = topic[2]
file_name = topic[3]
if callable(self._watch_cb):
self._watch_cb(source_name, file_name)
elif msg_type == 'unwatch':
source_name = topic[2]
file_name = topic[3]
if callable(self._unwatch_cb):
self._unwatch_cb(source_name, file_name)
[docs] def listen(self, topics: Iterable[str] = ("log|",)):
"""
Listens to incoming log messages on the ZeroMQ socket(s).
Blocks until `Ctrl + C` is pressed,
or ``SIGINT`` or ``SIGTERM`` is received by the process.
Returns immediately if either a bind address nor at least
one connect address is set.
:param topics:
The topic to subscribe with.
Can be used for selecting log messages from specific source.
Defaults to ``["log|"]``.
:type topics: Iterable[str]
"""
if not self._bind_address and not self._connect_addresses:
return
poller = Poller()
if self._bind_address:
self._pull_socket = self._ctx.socket(PULL)
self._pull_socket.bind('tcp://' + self._bind_address)
poller.register(self._pull_socket, POLLIN)
if self._connect_addresses:
self._sub_socket = self._ctx.socket(SUB)
for topic in topics:
self._sub_socket.setsockopt(
SUBSCRIBE, topic.encode(encoding=_TOPIC_ENCODING))
for address in self._connect_addresses:
self._sub_socket.connect('tcp://' + address)
poller.register(self._sub_socket, POLLIN)
try:
while not is_stopped():
events = dict(poller.poll(self._interval * 1000))
if self._pull_socket in events \
and events[self._pull_socket] == POLLIN:
data = self._pull_socket.recv_multipart(flags=NOBLOCK)
self._handle_message(data)
if self._sub_socket in events \
and events[self._sub_socket] == POLLIN:
data = self._sub_socket.recv_multipart(flags=NOBLOCK)
self._handle_message(data)
finally:
if self._pull_socket:
self._pull_socket.close()
self._pull_socket = None
if self._sub_socket:
self._sub_socket.close()
self._sub_socket = None


Commands
Work in progress! The side is under construction and will be updated soon!
Browser
browser [url] Open a website in the mainbrowser of the operating system.
url String The url to open the website
url String The name of the path variable
-np Modifier Bypass automatic https or http protocoll (No Protocoll)
CD (Change Directory)
cd [directory] Change directory.
directory String The name of the folder
directory String The path of the directory
directory String .. to go backwards
Help
Type
help <command> to see the instructions to use the command.
LS (List)
List all files and folders in directory.
MkDir (Make Directory)
mkdir [name] Create a new directory.
name String Name of the directory
Note
note <action> [name] Set or remove a note
action String Use add, remove or list the notes
name String The name of the note
RM (Remove)
rm [name] Remove a file or directory.
name String Name of the file or directory";
Variable
variable <action> [name] [url] Set or remove a path variable
action String Use add, remove or list the variables
name String The name of the path variable
url String The target of the path variable
Version
Display the current version of the DeskPlaner.


Andy Harmon
I'm a recently graduated software developer, former charity director and community activitst based in Salford, Greater Manchester. Alongside developing commercial products, I volunteer time to develop community projects and build technical solutions for driving change.
I'm always open to conenct with new projects and people!


Gloria * 1/2 (out of * * * * )
Directed by Sidney Lumet. Cast: Sharon Stone, Jean-Luke Figueroa, Jeremy Northam, Mike Starr, George C. Scott, Bonnie Bedelia, Cathy Moriarty, Sarita Choudhury. 1999 - 105 minutes. Rated R (for violence and profanity). Reviewed January 23, 1999.
One of the most blatantly obvious signs that often-acclaimed director Sidney Lumet's "Gloria," a remake of the 1980 John Cassavetes film, had absolutely no effect on me occurred when I was driving home from the theatre. Suddenly, I realized that since I had stood up from my theatre seat five minutes before, I had not thought once about the film I had just invested nearly two hours of my life in. When a movie is over, aren't we supposed to think about it for a while, and have a conversation about it with the acquaintances we have just watched it with? I thought so, but, for one, I saw this particular picture by myself, and #2, even if I had been with someone there wouldn't have been anything to talk about in the first place.
To be sure, "Gloria" begins with a stirring, rather poignant prologue in which a seven-year-old boy's family is brutally gunned down by mobsters, in search of a disc his father had with incriminating evidence on it. Right before the men broke in, of course, his father gave him the disc to escape with. Eventually, the boy, named Nicky Nunez (Jean-Luke Figueroa), is caught by the mobsters, and taken back to their apartment. Meanwhile, Gloria (Sharon Stone) has just gotten out of prison for a crime she didn't commit and returns to her ex-boyfriend (Jeremy Northam) to recieve the money he promised her for covering up his crime. When he refuses to give it to her, and then hears the group of men talking about killing Nicky, she leaves with him in order to save his life, but not before holding the men at gunpoint, stealing all of their money, and forcing them to strip nude. Gloria is the type of fast-talking, smart-mouthed New Yorker who always seems to get involved with the wrong people, and she never expected to be stuck with a kid, but she has a heart of gold (don't they always in this type of movie) and is only trying to protect the boy, whom she quickly begins to form a close bond with.
The previous incarnation of "Gloria" by Cassavetes and starring the luminous Gena Rowlands, remains unseen by me, but was no doubt superior, even though I can't really imagine how this considerably dull story could be transformed into an entertaining one, regardless of the director or stars. There is no doubt in my mind that director Lumet has stuck closely to the original, but the film itself is simply lifeless, with only an occasional laugh popping up here and there so that it isn't completely unbearable to watch. I liked, for example, a very funny climactic sequence where Gloria is deciding whether to leave the school she has left the boy at, and keeps turning the car around, then driving a little ways, then slamming on the brakes and turning around again. These bright moments, however, appear long and far between, and the majority of the film deals with the budding relationship between Nicky and Gloria, which is both painfully predictable and by-the-numbers. Throughout, my mind was repeatedly asking the question, "who really cares?"
As Gloria, Sharon Stone has adopted an over-the-top Brooklyn accent that honestly doesn't sound realistic at all. In the beginning, in fact, I was amazed at how amateurish Stone's performance was, but as the film progressed she got better. Although not one of her better turns, Stone does have a comic flare that refuses to be ignored. Jean-Luke Figeroa was fine as Nicky and a little more natural than the usual child actors who are so precocious they make you want to gag. All other actors who appeared were considerably wasted, none more than Cathy Moriarty, an entertaining actress in her own right, who is billed fourth and has all of one scene, as Gloria's friend whom she turns to for help.
Sony, the studio that released "Gloria," obviously does not have any faith in the film, and I don't blame them. They declined to screen the picture for critics, which is never a good sign, particularly with the high-profile people involved. Although how much money a movie makes does not determine how good it is (just look at the spectacular "In Dreams," which failed to even make the Top 10 last week), I have a suspicion "Gloria" is going to vanish from theaters faster than "Ishtar," judging from the opening night 7:00 p.m. showing I saw it at, where there were about ten to fifteen people present, counting myself. Although Stone can be an impressive actress (just watch her in 1995's "Casino" or 1996's "Last Dance" if you don't believe me) and Sidney Lumet can be a respectable director, there is no reasoning for why they thought the cliched story of "Gloria" was worth remaking or, for that matter, why Columbia Pictures agreed to finance it when they could have been making a picture that actually looked like it might have an inkling of a chance to be successful.
- Copyright 1999 by Dustin Putman < Dustin Putman's Film Haven >
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


About Me
Hi, I'm Matt, a Full Stack Developer. I've always wanted to be a programmer, and finally took the plunge to formalize my education in the fall of 2019. I studied at the University of Arizona's Extension Coding Boot Camp (Go Wildcats!) and graduated early summer of 2020. With the amazing curriculum at UofA, I was able to master CSS3, HTML5 and JavaScipt for the front end. For the backend I use MYSQL and MongoDB. I also learned JQuery, Bootstrap, Handlebars and React.js.
Since graduating with my UofA certificate, I've been continuing my education by learning Java, Python and Php.
My family is my biggest motivator. Not only did they support me during my education, but they are my biggest fans in all that I do involving programming. Take a look at my portfolio, which has been thoroughly approved by my 2 year old as "cool" and I hope you feel the same. Also feel free to look at my Resume


TDataGatewayCommand is command builder and executor class for TTableGateway and TActiveRecordGateway.
TDataGatewayCommand builds the TDbCommand for TTableGateway and TActiveRecordGateway commands such as find(), update(), insert(), etc, using the TDbCommandBuilder classes (database specific TDbCommandBuilder classes are used).
Once the command is built and the query parameters are binded, the OnCreateCommand event is raised. Event handlers for the OnCreateCommand event should not alter the Command property nor the Criteria property of the TDataGatewayEventParameter.
TDataGatewayCommand excutes the TDbCommands and returns the result obtained from the database (returned value depends on the method executed). The OnExecuteCommand event is raised after the command is executed and resulting data is set in the TDataGatewayResultEventParameter object's Result property.
Located in /Data/DataGateway/TDataGatewayCommand.php (line 37)
TComponent | --TDataGatewayCommand
Executes a delete command.
Calculates the AND/OR condition from dynamic method substrings using table meta data, allows for any AND-OR combinations.
Find one record matching the critera.
Find zero or more matching records for arbituary SQL.
Construct a "pk IN ('key1', 'key2', ...)" criteria.
Build the find command from the criteria. Limit, Offset and Ordering are applied if applicable.
Iterate through all the columns and returns the last insert id of the first column that has a sequence or serial.
Create the condition and parameters for find by primary.
Build sql command from the criteria. Limit, Offset and Ordering are applied if applicable.
Inserts a new record into the table. Each array key must correspond to a column name in the table unless a null value is permitted.
Raised when a command is prepared and parameter binding is completed.
The parameter object is TDataGatewayEventParameter of which the TDataGatewayEventParameter::getCommand property can be inspected to obtain the sql query to be executed.
Raised when a command is executed and the result from the database was returned.
The parameter object is TDataGatewayResultEventParameter of which the TDataGatewayEventParameter::getResult property contains the data return from the database. The data returned can be changed by setting the TDataGatewayEventParameter::setResult property.
Updates the table with new data.
Inherited From TComponent
TComponent::addParsedObject()
TComponent::attachEventHandler()
TComponent::canGetProperty()
TComponent::canSetProperty()
TComponent::createdOnTemplate()
TComponent::detachEventHandler()
TComponent::evaluateExpression()
TComponent::evaluateStatements()
TComponent::getEventHandlers()
TComponent::getSubProperty()
TComponent::hasEvent()
TComponent::hasEventHandler()
TComponent::hasProperty()
TComponent::raiseEvent()
TComponent::setSubProperty()
TComponent::__get()
TComponent::__set()
Documentation generated on Fri, 03 Jun 2011 16:23:42 +0200 by phpDocumentor 1.3.0RC4


--- layout: post permalink: bijouler.html Tags: Array NameOfCoupon: Bijouler Cash Back Summary: See our Bijouler Coupon Code, Bijouler Rebate, Bijouler Promo Code, Bijouler Discount, Bijouler Coupon Cash Back Rebate here. MetaKeywords: Bijouler Coupon Code, Bijouler Rebate, Bijouler Promo Code, Bijouler Cash Back Rebate, Bijouler Discount, Bijouler Coupon Image: images/29964.jpg LinkURL: http://www.shareasale.com/r.cfm?b=264924&u=412002&m=29964 affiliate_url_link: http://www.icouponblog.com/jane.php?id=6199 thesis_readmore: See the Bijouler Coupon thesis_thumb: http://www.icouponblog.com/tn.php?merchantURL=bijouler.com Title: Save 5.00% - Bijouler Coupon Code for bijouler.com. Bijouler Rebate & Discount thesis_description: Our Bijouler Discount Coupon Code for bijouler.com. We have the best Bijouler Rebate anywhere. thesis_keywords: Bijouler, Bijouler Coupon Code, Bijouler Discount, Bijouler Rebate product_name: Bijouler hop_url: http://www.icouponblog.com/hop.php?id=6199 ---
If you are looking for exquisite, one of a kind jewelry then visit bijouler.com. They specialize in handmade jewelry made from unusual gemstones. They offer free worldwide delivery on all items. Surprise your loved ones in India, the UK, Africa, Egypt, no matter where they are, you can send them a beautifully handcrafted jewelry from bijouler.com. It will bring great joys to their lives and they will appreciate your gesture greatly. Whether it’s a birthday, anniversary, Valentine or no occasion, love is best when expressed…Jewelry is an amazing form of expression especially when it is handcrafted or exquisite and exclusive. Buy from bijouler.com today.
bijouler.com is the best place to buy beautiful, spectacular and out of this world jewelry made from real pearls, gold, sterling silver and genuine gemstones. Get the best prices for the most beautiful pieces of jewelry. Our coupons will save you money. Buy rings, earrings, bracelets and more. visit bijouler.com.


Rogue Example
This example implements a simple text based game. Do you see the @
in the screenshot? That's you, the rogue. The #
characters are walls, and the dots represent floor. In a real game, other ASCII characters would represent all kinds of objects and creatures, for instance, ancient dragons (D
s) or food rations (%
s). But let's not get carried away. In this game, the rogue is simply running around in an empty room.
The rogue is moved with the keypad (2, 4, 8, 6). That aside, we have implemented a quit
command that triggers if the player types q
. The player is then asked if he/she really wants to quit.
Most games have commands that need more than one key press (we think of consecutive presses, i.e., not of several keys being pressed at the same time). In this game, only the quit
command falls under this category, but for the sake of argument, let's imagine a fully-fledged game with a rich set of commands. If we were to implement these by catching key events in keyPressEvent(), we would have to keep a lot of class member variables to track the sequence of keys already typed (or find some other way of deducing the current state of a command). This can easily lead to spaghetti, which is--as we all well know, I'm sure--unpleasant. With a state machine, on the other hand, separate states can wait for a single key press, and that makes our lives a lot simpler.
The example consists of two classes:
Window
draws the text display of the game and sets up the state machine. The window also has a status bar above the area in which the rouge moves.MovementTransition
is a transition that carries out a single move of the rogue.
Before we embark on a code walkthrough, it is necessary to take a closer look at the design of the machine. Here is a state chart that shows what we want to achieve:
The input state waits for a key press to start a new command. When receiving a key it recognizes, it transitions to one of the two commands of the game; though, as we will see, movement is handled by the transition itself. The quit state waits for the player to answer yes or no (by typing y
or n
) when asked whether he/she really wants to quit the game.
The chart demonstrates how we use one state to wait for a single key press. The press received may trigger one of the transitions connected to the state.
Window Class Definition
The Window
class is a widget that draws the text display of the game. It also sets up the state machine, i.e., creates and connects the states in the machine. It is the key events from this widget that are used by the machine.
class Window : public QWidget { Q_OBJECT Q_PROPERTY(QString status READ status WRITE setStatus) public: enum Direction { Up, Down, Left, Right }; Window(); void movePlayer(Direction direction); void setStatus(const QString &status); QString status() const; QSize sizeHint() const override; protected: void paintEvent(QPaintEvent *event) override;
Direction
specifies the direction in which the rogue is to move. We use this in movePlayer()
, which moves the rogue and repaints the window. The game has a status line above the area in which the rogue moves. The status
property contains the text of this line. We use a property because the QState class allows setting any Qt property when entered. More on this later.
private: void buildMachine(); void setupMap(); QChar map[WIDTH][HEIGHT]; int pX, pY; QStateMachine *machine; QString myStatus; };
The map
is an array with the characters that are currently displayed. We set up the array in setupMap()
, and update it when the rogue is moved. pX
and pY
is the current position of the rogue. WIDTH
and HEIGHT
are macros specifying the dimensions of the map.
The paintEvent()
function is left out of this walkthrough. We also do not discuss other code that does not concern the state machine (the setupMap()
, status()
, setStatus()
, movePlayer()
, and sizeHint()
functions). If you wish to take a look at the code, click on the link for the window.cpp
file at the top of this page.
Window Class Implementation
Here is the constructor of Window
:
Window::Window() { pX = 5; pY = 5; ... setupMap(); buildMachine(); }
The player starts off at position (5, 5). We then set up the map and statemachine. Let's proceed with the buildMachine()
function:
void Window::buildMachine() { machine = new QStateMachine; QState *inputState = new QState(machine); inputState->assignProperty(this, "status", "Move the rogue with 2, 4, 6, and 8"); MovementTransition *transition = new MovementTransition(this); inputState->addTransition(transition);
We enter inputState
when the machine is started and from the quitState
if the user wants to continue playing. We then set the status to a helpful reminder of how to play the game.
First, the Movement
transition is added to the input state. This will enable the rogue to be moved with the keypad. Notice that we don't set a target state for the movement transition. This will cause the transition to be triggered (and the onTransition() function to be invoked), but the machine will not leave the inputState
. If we had set inputState
as the target state, we would first have left and then entered the inputState
again.
QState *quitState = new QState(machine); quitState->assignProperty(this, "status", "Really quit(y/n)?"); QKeyEventTransition *yesTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Y); yesTransition->setTargetState(new QFinalState(machine)); quitState->addTransition(yesTransition); QKeyEventTransition *noTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_N); noTransition->setTargetState(inputState); quitState->addTransition(noTransition);
When we enter quitState
, we update the status bar of the window.
QKeyEventTransition
is a utility class that removes the hassle of implementing transitions for QKeyEvents. We simply need to specify the key on which the transition should trigger and the target state of the transition.
QKeyEventTransition *quitTransition = new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Q); quitTransition->setTargetState(quitState); inputState->addTransition(quitTransition);
The transition from inputState
allows triggering the quit state when the player types q
.
machine->setInitialState(inputState); connect(machine, SIGNAL(finished()), qApp, SLOT(quit())); machine->start(); }
The machine is set up, so it's time to start it.
The MovementTransition Class
MovementTransition
is triggered when the player request the rogue to be moved (by typing 2, 4, 6, or 8) when the machine is in the inputState
.
class MovementTransition : public QEventTransition { Q_OBJECT public: MovementTransition(Window *window) : QEventTransition(window, QEvent::KeyPress) { this->window = window; }
In the constructor, we tell QEventTransition to only send KeyPress events to the eventTest() function:
protected: bool eventTest(QEvent *event) override { if (event->type() == QEvent::StateMachineWrapped && static_cast<QStateMachine::WrappedEvent *>(event)->event()->type() == QEvent::KeyPress) { QEvent *wrappedEvent = static_cast<QStateMachine::WrappedEvent *>(event)->event(); QKeyEvent *keyEvent = static_cast<QKeyEvent *>(wrappedEvent); int key = keyEvent->key(); return key == Qt::Key_2 || key == Qt::Key_8 || key == Qt::Key_6 || key == Qt::Key_4 || key == Qt::Key_Down || key == Qt::Key_Up || key == Qt::Key_Right || key == Qt::Key_Left; } return false; }
The KeyPress events come wrapped in QStateMachine::WrappedEvents. event
must be confirmed to be a wrapped event because Qt uses other events internally. After that, it is simply a matter of checking which key has been pressed.
Let's move on to the onTransition()
function:
void onTransition(QEvent *event) override { QKeyEvent *keyEvent = static_cast<QKeyEvent *>( static_cast<QStateMachine::WrappedEvent *>(event)->event()); int key = keyEvent->key(); switch (key) { case Qt::Key_Left: case Qt::Key_4: window->movePlayer(Window::Left); break; case Qt::Key_Up: case Qt::Key_8: window->movePlayer(Window::Up); break; case Qt::Key_Right: case Qt::Key_6: window->movePlayer(Window::Right); break; case Qt::Key_Down: case Qt::Key_2: window->movePlayer(Window::Down); break; default: ; } }
When onTransition()
is invoked, we know that we have a KeyPress event with 2, 4, 6, or 8, and can ask Window
to move the player.
The Roguelike Tradition
You might have been wondering why the game features a rogue. Well, these kinds of text based dungeon exploration games date back to a game called, yes, "Rogue". Although outflanked by the technology of modern 3D computer games, roguelikes have a solid community of hard-core, devoted followers.
Playing these games can be surprisingly addictive (despite the lack of graphics). Angband, the perhaps most well-known rougelike, is found here: http://rephial.org/.
Files:


The reaeration empirical method was run on the CDEC_2010-03-02 dataset, with depth set to 1.021457, velocity set to 0.653112, barpress set to 760, sunrise set to<PHONE_NUMBER> and sunset set to<PHONE_NUMBER>. The metabolism 03-02-2010 results are available online.
The Metabolism 03-02-2010 result was derived from the CDEC_2010-03-02 dataset.
Reaeration empirical performs two main types of analyses in the initial dataset. Fisrt, the RaerationEmpirical step compares the Dissolved Oxygen, Temperature, Depth, and Velocity to determine the rate of reaeration, or the K2 value. Then, the Metabolism step is executed to produce the target results.
The Reaeration empirical method has 3 steps. First, the input data is analyzed by Waterflow_Hourly_Averages, followed by Raeration_Empirica (using the output from Waterflow_Hourly_Averages). The final step is the metabolism step, which produced the Metabolism_03-02-2010 results.
Reaeration empirical performs two main types of analyses in the initial dataset. The RaerationEmpirical step compares the Dissolved Oxygen, Temperature, Depth, and Velocity to determine the rate of reaeration, or the K2 value. The relationship between these inputs is determined through regression on past data. Reaeration is the process by which oxygen is absorbed by the stream from the air. The rearation empirical step uses the ReaerationCMNode software implementation.
After applying the HourlyAverages step, the Metabolism step is executed to produce the target results. The metabolism step uses the MetabolismDay software implementation.


March 11
For God so loved the world, that he gave his only begotten Son. John 3:16
For God so loved the world that He gave...and He gave...and He gave.
That is the message the Bible brings us from beginning to end. It sounds simple enough. Yet few of us really comprehend it.
We can understand the idea of a God of power. We can understand a God who desires to be served. But an Almighty God who loves us so much that He desires, above all, to give to us? That can be hard to believe.
For thousands of years, God has been working to drop the revelation of His love into the hearts of men. He's made loving promises of blessing and protection. But He's always faced that same obstacle--human beings who just couldn't bring themselves to believe those promises were true.
The story of Abram is a perfect example. He wasn't accustomed to the idea of a God who gives. After all, he'd grown up as a worshiper of the moon, and the moon had certainly never seemed interested in doing anything for him. Then he encountered El Shaddai, the greatest Being of all. The one Almighty God. And the first thing this El Shaddai wanted to do was give to him.
God's promises so astounded Abram that he couldn't believe them. "Lord," he asked, "how can I know I'm really going to receive these things?" (Gen. 15:8).
Do you know how God answered him? By cutting a blood covenant with him. That covenant settled forever any question Abram could ever have about God's love and loyalty. Once blood had been shed, he knew God meant what He said.
God did the same thing for you. He cut a blood covenant with you. And He sacrificed His own Son to do it. Jesus' broken body and shed blood have become the eternal proof of God's love for you. Through Communion, He's urged you to remember them again and again so that when your faith in His promises begins to waver, you "might have a strong consolation" (Heb. 6:18).
Get a revelation of God's love for you by meditating on the covenant He's made with you. Get out the bread and the cup. Go before the Lord with them and take Communion thinking about the body and blood of Jesus that enables you to be a blood-covenant member of the family of Almighty God. Let them settle forever the question of God's love for you. You'll never again have to doubt His promises once you believe in His love.
Scripture Reading: Genesis 15


Netglow was founded upon our undying passion for eSports and our strong ambition to advocate for the best talent within the professional gaming and streaming industries. We seek to bring brands together with influencers who create outstanding content through services such as YouTube and Twitch.
We envision a team of intelligent, hard-working, dedicated, and well-rounded young adults who share a love for all things gaming. This vision is being made into a reality, we know the talent exists. We're just waiting to represent it.
We strive to build the best partnerships for our talent. Our brand seeks to brighten the spotlight on our talent's character and stories, so that their worldwide audience can bloom and grow.
We live for excitement, this is why we strive to build the best partnerships for our talent. Whether it’s; collaborations, attending events or creating special content such as videos or graphics. We can work with you on planning and enacting these projects, so that your brand can grow.
Whether it's a single campaign or part of a wider strategy, Netglow provides the perfect influencers for every occasion that can flawlessly represent your brand in any scenario. Allow us to help you manage and plan your engagement with influencers, so that we can ensure a successful campaign and a meaningful partnership.


Three Andhra women not allowed Sabarimala Darshan
Sabarimala: The Kerala police on Saturday did not allow three women, who were part of a group, to go to the Sabarimala temple to pray after checking the identity cards of the women. The temple tradition disallows women in the age group of 10 to 50 years to enter the temple precinct. The two-month-long Sabarimala temple festival officially opens for pilgrims on Sunday at 5 a.m. However, it opens today at 5 p.m. for religious rituals to be performed by the temple priest and ‘tantris.’ The three women who were barred toady came from Vijayawada in Andhra Pradesh. They were part of a group of pilgrims who were stopped for checking by the police at Pamba base camp. Sources said the three women were separated from the group as the police suspected them to be in the age group of 10-50 years. (IANS)
Also Read: VHP sees no gender discrimination in Sabarimala temple
Also Watch: Govt all set to push for the contentious Citizenship Bill in the winter session of Parliament


How to complie
This article is an open source project development document written to help some users who want to become developers.
Get maixpy open source project
Please prepare the linux system environment (WSL on Windows is also possible), hook up the XXX proxy, enter git clone https://github.com/sipeed/MaixPy
to pull the MaixPy warehouse code and submodules, and make sure to read the catalog after you get it Build.md document under.
Students who do not have an agent can use the github mirror station list (
https://github.com/rc1844/fastgithub
) to accelerate the pull of the maixpy repository. Please do not use gitee to pull the maixpy repository, which will drop the submodule repository.
juwan@juwan-N85-N870HL:~$ git clone https://gitclone.com/github.com/sipeed/MaixPy
Cloning to'MaixPy'...
remote: Object count: 77517, completed.
remote: Compressed object: 100% (20929/20929), complete.
remote: Total 77517 (delta 56791), reused 76050 (delta 55761)
Among the recipients: 100% (77517/77517), 53.62 MiB | 972.00 KiB/s, completed.
Processing delta: 100% (56791/56791), complete.
juwan@juwan-N85-N870HL:~$ cd MaixPy/
juwan@juwan-N85-N870HL:~/MaixPy$ git submodule update --recursive --init
The submodule'components/kendryte_sdk/kendryte-standalone-sdk' (https://github.com/sipeed/kendryte-standalone-sdk) has been registered to the path'components/kendryte_sdk/kendryte-standalone-sdk'
The submodule'components/micropython/core' (https://github.com/micropython/micropython.git) has been registered to the path'components/micropython/core'
The submodule'components/micropython/port/src/lvgl/lv_bindings' (https://github.com/littlevgl/lv_binding_micropython.git) has been registered to the path'components/micropython/port/src/lvgl/lv_bindings'
The submodule'components/micropython/port/src/ulab/micropython-ulab' (https://github.com/Neutree/micropython-ulab.git) has been updated to the path'components/micropython/port/src/ulab/micropython -ulab' sign up
The submodule'components/spiffs/core' (https://github.com/pellepl/spiffs.git) has been registered to the path'components/spiffs/core'
The submodule'tools/flash/kflash_py' (https://github.com/sipeed/kflash.py.git) has been registered to the path'tools/flash/kflash_py'
The submodule'tools/kconfig/Kconfiglib' (https://github.com/ulfalizer/Kconfiglib.git) has been registered to the path'tools/kconfig/Kconfiglib'
The submodule'tools/spiffs/mkspiffs' (https://github.com/igrr/mkspiffs.git) has been registered to the path'tools/spiffs/mkspiffs'
Cloning to'/home/juwan/MaixPy/components/kendryte_sdk/kendryte-standalone-sdk'...
Cloning to'/home/juwan/MaixPy/components/micropython/core'...
Note that there is no acceleration in pulling the sub-repository after this, and you will try to pull it from github. You can also use the same method to pull the sub-module location separately (defined in .gitmodules
). This document cannot help you Solve network problems.
If https://gitclone.com is down, try to find other lines by yourself.
How to confirm whether the final submodule is pulled completely, you can enter git submodule status
, please do not compile if it is incomplete, there will be errors.
juwan@juwan-N85-N870HL:~/Desktop/maixpy$ git submodule status
7fdb511fe61026eec5874885de5981c4f60f664d components/kendryte_sdk/kendryte-standalone-sdk (v0.5.2-181-g7fdb511)
ced340d739e84737dd5c8e6b4ab9af2ea44e29e7 components/micropython/core (v1.11-64-gced340d73)
ddf09164ee1711a61169030a7ee8bf370ee5743f components/micropython/port/src/lvgl/lv_bindings (remotes/origin/dev-6.0-32-gddf0916)
c315a571df49a19b843f7dffc300c21ccb7d4edd components/micropython/port/src/ulab/micropython-ulab (0.24-27-gc315a57)
ec68ba8208d7550860e4e78299d58a529b88bf85 components/spiffs/core (0.2-234-gec68ba8)
1ef6f4c0b2cb8b1872b6ffe9337f4e02d5487fa6 tools/flash/kflash_py (v1.0-79-g1ef6f4c)
53c72959ac4d71f99913e4b0eea99261a6585430 tools/kconfig/Kconfiglib (v12.12.1-14-g53c7295)
983970e40ff381d95d68a9bddff70c4d9921021b tools/spiffs/mkspiffs (0.2.3-6-g983970e)
Compile maixpy open source project
This section assumes that you do not have any experience in building cross-compilation chains.
First press build.md to perform various operations in order. If you don’t speak English, you can open a translator.
The steps are as follows:
- nstall the necessary compilation tools and Python modules for the linux environment, and make sure cmake / make / python3 are available.
- Set the toolchain toolchain to the directory
/opt/kendryte-toolchain/
in the system to facilitate the SDK to find the compilation tool, and ensure that the /opt/kendryte-toolchain/bin/riscv64-unknown-elf-gcc compilation tool exists. - Enter
cd projects/maixpy_k210
under the specific hardware project of MaixPy and enterpython3 project.py build
to start compiling.
This is the end of the entire compilation step. After successful compilation, you will get a build folder in the projects/maixpy_k210
directory, which contains the following files:
- maixpy.bin will be burned to the K210 firmware at address 0x000000.
- maixpy.txt The content of the decompiled code corresponding to the current firmware, to help you check the information of the pointer address of the core dump.
Other files are .a and .o intermediate files generated during the compilation process and can be ignored.
Burn maixpy firmware to your hardware
Now you get the maixpy.bin firmware, insert the hardware, and then use python3 project.py -B goE -p /dev/ttyUSB1 -b 1500000 flash
to burn the hardware. Take the -B
parameter as an example.
juwan@juwan-N85-N870HL:~/Desktop/maixpy/projects/maixpy_k210$ python3 project.py -h
- SDK_PATH:/home/juwan/Desktop/maixpy
maixpy
usage: project.py [-h] [-p PORT] [-b BAUDRATE] [-t] [-n] [-s] [-B {dan,bit,bit_mic,goE,goD,maixduino,kd233,auto }] [-S] [--toolchain PATH] [--toolchain-prefix PREFIX]
[--config_file PATH] [--verbose]
{config,build,rebuild,menuconfig,clean,distclean,clean_conf,flash}
build tool, e.g. `python project.py build`
Among them, -B goE
is the choice of version, and the optional items are dan, bit, bit_mic, goE, goD, maixduino, kd233, auto
indicating the burning method, which has a lot to do with the specific hardware.
Bit usually corresponds to the chip using CH340.
maixduino usually corresponds to the chip using CH552.
Specifically, you can try a variety of options, and you can also choose the BAUDRATE option of burning frequency 115200 and 1.500000. Of course, no matter which configuration, as long as it can be burned in, you need to check the help description of -h for more usage methods.
The common burning process is as follows:
➜ maixpy_k210_minimum git:(master) ✗ sudo kflash -b 1500000 -p /dev/ttyUSB0 build/maixpy.bin
[sudo] fqr password:
[INFO] COM Port Selected Manually: /dev/ttyUSB0
[INFO] Default baudrate is 115200, later it may be changed to the value you set.
[INFO] Trying to Enter the ISP Mode...
._
[INFO] Automatically detected goE/kd233
[INFO] Greeting Message Detected, Start Downloading ISP
Downloading ISP: |============================================ ================================================= ============| 100.0% 10kiB/s
[INFO] Booting From 0x80000000
[INFO] Wait For 0.1 second for ISP to Boot
[INFO] Boot to Flashmode Successfully
[INFO] Selected Baudrate: 1500000
[INFO] Baudrate changed, greeting with ISP again ...
[INFO] Boot to Flashmode Successfully
[INFO] Selected Flash: On-Board
[INFO] Initialization flash Successfully
Programming BIN: |============================================= ================================================= ============| 100.0% 47kiB/s
[INFO] Rebooting...
Command line to connect hardware & run code
You can basically use it up to this step.
Here is a recommendation for some quick operations of linux or micropython during development. First, you can use minicom or picocom serial tool to enter the MicroPython terminal (add && picocom /dev/ttyUSB0 -b 115200
after the burning command), then When entering micropython, you can press Ctrl + E to enter the paste mode, and then paste the code and enter Ctrl + D to end the input of the running code.
>>>
hello world!
>>>
In this way, you have completed quick verification and development, but if you want to debug a certain piece of functional code, you can upload the code directly through the command line via mpfshell-lite , Reset and run, and then report an error and debug.
Low-level development of dynamic languages often operate in this way, so we want to thank all developers who do interpreter interfaces for doing a lot of interface verification.
MaixPy project application description
Assuming that you already know how to use MaixPy project to develop, compile, and burn, then I will introduce the usage of some tools in depth, here only some common usage will be explained, and no detailed explanation will be expanded.
Introduce cmake's project compilation method
cmake is a tool that compiles and generates Makefile after writing code and rules through CMakeLists.txt. The usage and details are independent of Baidu. Here is a simple structured cmake project Get_static_library_by_cmake for You run and learn by reference.
Before cmake, makefiles were used for project management. Until today, micropython officially still uses a double-layer Makefile + inclue (makefile) project to manage multi-version hardware.
But MaixPy only adds micropython to its environment as a dependent library package, so in fact the software architecture design of MaixPy is built around the form of K210 software components.
So you can go to the hello_world project in the maixpy folder to see how it is composed.
- hello_world
- build
- compile
- main
- CMakeLists.txt
- config_defaults.mk
- project.py
The MaixPy project has prepared a template for you to build the K210 project. Ignore the process of project construction here, and focus on the project configuration part that needs to be compiled and linked, that is, CMakeLists.txt under main. Its content is as follows.
############### Add include ##################
# list(APPEND ADD_INCLUDE "include"
#)
# list(APPEND ADD_PRIVATE_INCLUDE "")
############################################
############ Add source files #################
list(APPEND ADD_SRCS "src/main.cpp"
)
# aux_source_directory(src ADD_SRCS)
# list(REMOVE_ITEM COMPONENT_SRCS "src/test2.c")
############################################
###### Add required/dependent components ######
list(APPEND ADD_REQUIREMENTS kendryte_sdk)
############################################
############ Add static libs ##################
# list(APPEND ADD_STATIC_LIB "lib/libtest.a")
############################################
register_component()
You can see that ADD_SRCS
links a src/main.cpp
code file as the program entry.
You can load modules from other places through ADD_REQUIREMENTS
. For example, list(APPEND ADD_REQUIREMENTS kendryte_sdk)
requests the SDK package kendryte_sdk
.
What if you want to link your own nncase library? What about other library codes?
It can be directly changed to the code of LINK_DIRECTORIES(/home/juwan/maixpy/projects/maixpy_old/main/src/nncase)
under the absolute path. The premise of this is that the library is provided by the cmake project of.
Here is a demonstration of how to call your own nncase library during compilation, and read the project after combining these key information. It should be easier to use.
How to package the micropython spiffs file system and share it
If you use MaixPy for development, you will find that MaixUI provides a file system file (img). When you flash the same img as the UI system, you will directly enter the UI interface after burning.
You need to know that MicroPython is a program starting from 0x0. In the program, the VFS (virtual file system) will be constructed in the [0xD00000, (0xD00000 + 0x300000)) interval of Flash through spiffs, which is defined in maixpy/projects/maixpy_xxxxx/config_defaults.mk owned.
CONFIG_SPIFFS_SIZE=0x300000
CONFIG_SPIFFS_START_ADDR=0xD00000
Only the use of tools is discussed here, without detailed explanation of its implementation.
And spiffs does not support directory structure, then we will find that the file name of ui's img in flash will have a name like lib/core.py
, Under normal circumstances, it is impossible for us to create this file, so we need to package it with tools.
There is a gen_spiffs_image.py script in the tools/spiffs/mkspiffs directory to complete the function of this packaged image. For usage, please refer to the instructions in tools/spiffs/README.md.
- Prepare an fs folder under the spiffs directory, which contains the code or resource file content you want to package.
- Execute
python gen_spiffs_image.py ../../projects/maixpy_k210/config_defaults.mk
to get the maixpy_spiffs.img binary file. - Burn the img obtained above to 0xD00000 to restore the content in the micropython file system.
 This is actually the same as publishing a system image based on a Linux system. of.
Now, have you learned it?
MaixPy's continuous integration service (Travis CI)
Travis CI provides continuous integration services (Continuous Integration, CI for short). It binds the projects on Github, as long as there is new code, it will be automatically crawled. Then, provide a running environment, perform tests, complete the build, and deploy to the server.
Mention that MaixPy uses travis + tools/release.sh to compile the project and upload the compilation directory to the release server to complete the daily build. This is common in the automated build and compilation of various packages. You may be interested Try it yourself.
How to better read open source project source code
Having said that, from a personal point of view, in addition to the basic requirement of reading code, if you want to better read the source code, there are different organizational structures for different projects. Any beginner who has just entered the industry , You can use the project you have experienced as an entry point, and gradually establish a complete software engineering awareness from the aspects of project architecture, source code, compilation, testing, and software release. It is also a good method to conduct in-depth knowledge learning around this, I hope you You can build a complete software engineering system through this article.
Final reference
- bing.com + keyword + yourself


Replaces all parameters of a method or closure with a map. Accordingly, replaces parameter occurrences with appropriate entries of new map argument.


Given an identifier for an ORE document, retrieve and parse, then for each agggregated PID, determine if system metadata is available and whether it appears in the search index.
Environment:
Base URL:
PID:
Encoded PID:
Request:
ORE Object
URL:


com.punchline.javalib.entities.components.physical
Interfaces
Transform
Velocity
Classes
Body
Particle


Step 3 - Coding: calculator
Following Test-Driven Development (TDD) principles, we'll now code the software for the calculator software system.
For the purpose of demonstration, we use different programming languages to achieve the same goal.
Step 3.1 - Coding in C#: calculator
Step 3.2 - Coding in Java: calculator
Step 3.3 - Coding in JavaScript: calculator
Step 3.4 - Coding in Python: calculator
GitHub
As we created a repository called 'calculator' at the start of our use case, we will now create a branch for our code in Python, as follows.
cd calculator
git branch python
Next, change our current branch to the 'python' branch.
git checkout python
From here on we will add and edit code for python in this python branch, in a newly created directory called python.
mkdir python
cd python
To see if Python is installed, type the below on your command line.
py -v
To see if PyTest is installed, type the below on your command line.
pytest -v
If not already installed, install pytest as follows
pip3 install pytest
Create a file `calculator.py` with the following content:
# calculator.py class Calculator(object): def __init__(self, message = 'Hello World!'): self.message = message
Add the new file to git:
git add calculator.py
Create a file `test_calculator.py` with the following content:
# test_calculator.py import unittest from calculator import Calculator class CalculatorTestCase(unittest.TestCase): def setUp(self): self.calculator = Calculator() def test_message(self): self.assertEqual(self.calculator.message, 'Hello World!', msg='Message Invalid.')
Add the new file to git:
git add test_calculator.py
Create a file '.gitignore' with the following content:
__pycache__ *.py[cod] .DS_Store
Add the new file to git:
git add .gitignore
Run
pytest test_calculator.pyand PyTest will print a message alike this:
============================= test session starts ============================= platform win32 -- Python 3.5.2, pytest-3.4.0, py-1.5.2, pluggy-0.6.0 rootdir: C:\Users\user\Source\Repos\vanHeemstraSystems\calculator\python, inifile: collected 1 item test_calculator.py . [100%] ========================== 1 passed in 0.48 seconds ===========================
Commit your changes:
git commit -m "first unit test"
And push your changes back to the 'python' branch
git push --set-upstream origin python
Check the status to verify that all has been committed:
git status
You just successfully wrote your first test using PyTest!
more to follow...


Imports an SSL/TLS certificate into AWS Certificate Manager (ACM) to use with ACM's integrated AWS services .
Note
ACM does not provide managed renewal for certificates that you import.
For more information about importing certificates into ACM, including the differences between certificates that you import and those that ACM provides, see Importing Certificates in the AWS Certificate Manager User Guide .
To import a certificate, you must provide the certificate and the matching private key. When the certificate is not self-signed, you must also provide a certificate chain. You can omit the certificate chain when importing a self-signed certificate.
The certificate, private key, and certificate chain must be PEM-encoded. For more information about converting these items to PEM format, see Importing Certificates Troubleshooting in the AWS Certificate Manager User Guide .
To import a new certificate, omit the CertificateArn field. Include this field only when you want to replace a previously imported certificate.
This operation returns the Amazon Resource Name (ARN) of the imported certificate.
See also: AWS API Documentation
import-certificate
[--certificate-arn <value>]
--certificate <value>
--private-key <value>
[--certificate-chain <value>]
[--cli-input-json <value>]
[--generate-cli-skeleton <value>]
The Amazon Resource Name (ARN) of an imported certificate to replace. To import a new certificate, omit this field.
The certificate to import. It must meet the following requirements:
- Must be PEM-encoded.
- Must contain a 1024-bit or 2048-bit RSA public key.
- Must be valid at the time of import. You cannot import a certificate before its validity period begins (the certificate's NotBefore date) or after it expires (the certificate's NotAfter date).
The private key that matches the public key in the certificate. It must meet the following requirements:
- Must be PEM-encoded.
- Must be unencrypted. You cannot import a private key that is protected by a password or passphrase.
The certificate chain. It must be PEM-encoded.
--cli-input-json (string) Performs service operation based on the JSON string provided. The JSON string follows the format provided by --generate-cli-skeleton. If other arguments are provided on the command line, the CLI values will override the JSON-provided values.
--generate-cli-skeleton (string) Prints a JSON skeleton to standard output without sending an API request. If provided with no value or the value input, prints a sample input JSON that can be used as an argument for --cli-input-json. If provided with the value output, it validates the command inputs and returns a sample output JSON for that command.


CVE Quality Workgroup Report: CVEs assigned by LGE
CVE-2022-23727
CVE-2022-23728
CVE-2022-23729
CVE-2022-23730
CVE-2022-23731


Computers have become a major factor in the development and operation of the modern industry. From providing means of communications, to operating machines, to facilitating international commerce, to systems animation, computers and their related software programs makes things possible.
The Computer Software Engineering Technology program prepares students to design, develop, and build customized software programs for specific applications. Specifically, students will learn basic programming, how to interpret specifications, application of software architecture, verification and validation principles, and software performance standards. Students will create software programs which address known specifications. The program emphasizes a practical hands-on education as software projects are required each semester.
Upon completion of the program, graduates will find a wealth of employment opportunities in a variety of businesses and industries. Unlike some disciplines which are tied directly to a specific technical area, graduates of this program will work in small businesses, large industries, private organizations, software specialty businesses, IT Department, Government, and other agencies. Job titles might include:
A graduate of this program will be able to do the following: