diff --git a/bob/learn/misc/gaussian.cpp b/bob/learn/misc/gaussian.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..43a18509b77101b94d362f0a70d4f6fe329cb123
--- /dev/null
+++ b/bob/learn/misc/gaussian.cpp
@@ -0,0 +1,103 @@
+/**
+ * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
+ * @date Fri 21 Nov 10:38:48 2013
+ *
+ * @brief Python API for bob::learn::em
+ *
+ * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
+ */
+
+#include "main.h"
+
+/******************************************************************/
+/************ Constructor Section *********************************/
+/******************************************************************/
+
+static auto Gaussian_doc = bob::extension::ClassDoc(
+  BOB_EXT_MODULE_PREFIX ".Gaussian",
+  "This class implements a multivariate diagonal Gaussian distribution"
+).add_constructor(
+  bob::extension::FunctionDoc(
+    "__init__",
+    "Constructs a new multivariate gaussian object",
+    "",
+    true
+  )
+  .add_prototype("[n_inputs]")
+  //.add_prototype("tan_triggs", "")
+  //.add_parameter("gamma", "float", "[default: ``0.2``] The value of gamma for the gamma correction")
+  //.add_parameter("sigma0", "float", "[default: ``1.``] The standard deviation of the inner Gaussian")
+  //.add_parameter("sigma1", "float", "[default: ``2.``] The standard deviation of the outer Gaussian")
+  //.add_parameter("radius", "int", "[default: ``2``] The radius of the Difference of Gaussians filter along both axes (size of the kernel=2*radius+1)")
+  //.add_parameter("threshold", "float", "[default: ``10.``] The threshold used for the contrast equalization")
+  //.add_parameter("alpha", "float", "[default: ``0.1``] The alpha value used for the contrast equalization")
+  //.add_parameter("border", ":py:class:`bob.sp.BorderType`", "[default: ``bob.sp.BorderType.Mirror``] The extrapolation method used by the convolution at the border")
+  //.add_parameter("tan_triggs", ":py:class:`bob.ip.base.TanTriggs`", "The TanTriggs object to use for copy-construction")
+);
+
+
+static int PyBobLearnMiscGaussian_init(PyBobLearnMiscGaussianObject* self, PyObject* args, PyObject* kwargs) {
+  TRY
+
+  char* kwlist1[] = {c("n_inputs")};
+  //char* kwlist2[] = {c("tan_triggs"), NULL};
+
+  // get the number of command line arguments
+  Py_ssize_t nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0);
+
+
+  /*
+  PyObject* k = Py_BuildValue("s", kwlist2[0]);
+  auto k_ = make_safe(k);
+  if (nargs == 1 && ((args && PyTuple_Size(args) == 1 && PyBobIpBaseTanTriggs_Check(PyTuple_GET_ITEM(args,0))) || (kwargs && PyDict_Contains(kwargs, k)))){
+    // copy construct
+    PyBobIpBaseTanTriggsObject* tt;
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist2, &PyBobIpBaseTanTriggs_Type, &tt)) return -1;
+
+    self->cxx.reset(new bob::ip::base::TanTriggs(*tt->cxx));
+    return 0;
+  }*/
+
+  size_t n_inputs=0;
+  self->cxx.reset(new bob::learn::misc::Gaussian(n_inputs));
+  return 0;
+
+  CATCH("cannot create Gaussian", -1)
+}
+
+
+/******************************************************************/
+/************ Module Section **************************************/
+/******************************************************************/
+
+// Define the Gaussian type struct; will be initialized later
+PyTypeObject PyBobLearnMiscGaussian_Type = {
+  PyVarObject_HEAD_INIT(0,0)
+  0
+};
+
+bool init_BobLearnMiscGaussian(PyObject* module)
+{
+  // initialize the type struct
+  PyBobLearnMiscGaussian_Type.tp_name = Gaussian_doc.name();
+  PyBobLearnMiscGaussian_Type.tp_basicsize = sizeof(PyBobLearnMiscGaussianObject);
+  PyBobLearnMiscGaussian_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+  PyBobLearnMiscGaussian_Type.tp_doc = Gaussian_doc.doc();
+
+  // set the functions
+  PyBobLearnMiscGaussian_Type.tp_new = PyType_GenericNew;
+  PyBobLearnMiscGaussian_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnMiscGaussian_init);
+  //PyBobLearnMiscGaussian_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobIpBaseTanTriggs_delete);
+  //PyBobLearnMiscGaussian_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobIpBaseTanTriggs_RichCompare);
+  //PyBobLearnMiscGaussian_Type.tp_methods = PyBobIpBaseTanTriggs_methods;
+  //PyBobLearnMiscGaussian_Type.tp_getset = PyBobIpBaseTanTriggs_getseters;
+  //PyBobLearnMiscGaussian_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobIpBaseTanTriggs_process);
+
+  // check that everything is fine
+  if (PyType_Ready(&PyBobLearnMiscGaussian_Type) < 0) return false;
+
+  // add the type to the module
+  Py_INCREF(&PyBobLearnMiscGaussian_Type);
+  return PyModule_AddObject(module, "Gaussian", (PyObject*)&PyBobLearnMiscGaussian_Type) >= 0;
+}
+
diff --git a/bob/learn/misc/include/bob.learn.misc/api.h b/bob/learn/misc/include/bob.learn.misc/api.h
new file mode 100644
index 0000000000000000000000000000000000000000..44208e5cc7b7a10c8d7605396e3227b824fa289d
--- /dev/null
+++ b/bob/learn/misc/include/bob.learn.misc/api.h
@@ -0,0 +1,127 @@
+/**
+ * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
+ * @date Fri 21 Nov 10:38:48 2013
+ *
+ * @brief Python API for bob::learn::em
+ */
+
+#ifndef BOB_LEARN_EM_API_H
+#define BOB_LEARN_EM_API_H
+
+/* Define Module Name and Prefix for other Modules
+   Note: We cannot use BOB_EXT_* macros here, unfortunately */
+#define BOB_LEARN_EM_PREFIX    "bob.learn.misc"
+#define BOB_LEARN_EM_FULL_NAME "bob.learn.misc._library"
+
+#include <Python.h>
+
+#include <bob.learn.misc/config.h>
+#include <boost/shared_ptr.hpp>
+
+/*******************
+ * C API functions *
+ *******************/
+
+/* Enum defining entries in the function table */
+enum _PyBobLearnMisc_ENUM{
+  PyBobLearnMisc_APIVersion_NUM = 0,
+  // bindings
+  ////PyBobIpBaseLBP_Type_NUM,
+  ////PyBobIpBaseLBP_Check_NUM,
+  ////PyBobIpBaseLBP_Converter_NUM,
+  // Total number of C API pointers
+  PyBobLearnMisc_API_pointers
+};
+
+
+#ifdef BOB_LEARN_EM_MODULE
+
+  /* This section is used when compiling `bob.io.base' itself */
+
+  /**************
+   * Versioning *
+   **************/
+
+  extern int PyBobLearnMisc_APIVersion;
+
+#else // BOB_LEARN_EM_MODULE
+
+  /* This section is used in modules that use `bob.io.base's' C-API */
+
+#if defined(NO_IMPORT_ARRAY)
+  extern void **PyBobLearnMisc_API;
+#elif defined(PY_ARRAY_UNIQUE_SYMBOL)
+  void **PyBobLearnMisc_API;
+#else
+  static void **PyBobLearnMisc_API=NULL;
+#endif
+
+  /**************
+   * Versioning *
+   **************/
+
+#define PyBobLearnMisc_APIVersion (*(int *)PyBobLearnMisc_API[PyBobLearnMisc_APIVersion_NUM])
+
+#if !defined(NO_IMPORT_ARRAY)
+
+  /**
+   * Returns -1 on error, 0 on success.
+   */
+  static int import_bob_learn_misc(void) {
+
+    PyObject *c_api_object;
+    PyObject *module;
+
+    module = PyImport_ImportModule(BOB_LEARN_EM_FULL_NAME);
+
+    if (module == NULL) return -1;
+
+    c_api_object = PyObject_GetAttrString(module, "_C_API");
+
+    if (c_api_object == NULL) {
+      Py_DECREF(module);
+      return -1;
+    }
+
+#if PY_VERSION_HEX >= 0x02070000
+    if (PyCapsule_CheckExact(c_api_object)) {
+      PyBobLearnMisc_API = (void **)PyCapsule_GetPointer(c_api_object, PyCapsule_GetName(c_api_object));
+    }
+#else
+    if (PyCObject_Check(c_api_object)) {
+      PyBobLearnMisc_API = (void **)PyCObject_AsVoidPtr(c_api_object);
+    }
+#endif
+
+    Py_DECREF(c_api_object);
+    Py_DECREF(module);
+
+    if (!PyBobLearnMisc_API) {
+      PyErr_SetString(PyExc_ImportError, "cannot find C/C++ API "
+#if PY_VERSION_HEX >= 0x02070000
+          "capsule"
+#else
+          "cobject"
+#endif
+          " at `" BOB_LEARN_EM_FULL_NAME "._C_API'");
+      return -1;
+    }
+
+    /* Checks that the imported version matches the compiled version */
+    int imported_version = *(int*)PyBobLearnMisc_API[PyBobLearnMisc_APIVersion_NUM];
+
+    if (BOB_LEARN_MISC_API_VERSION != imported_version) {
+      PyErr_Format(PyExc_ImportError, BOB_LEARN_EM_FULL_NAME " import error: you compiled against API version 0x%04x, but are now importing an API with version 0x%04x which is not compatible - check your Python runtime environment for errors", BOB_LEARN_MISC_API_VERSION, imported_version);
+      return -1;
+    }
+
+    /* If you get to this point, all is good */
+    return 0;
+
+  }
+
+#endif //!defined(NO_IMPORT_ARRAY)
+
+#endif /* BOB_LEARN_EM_MODULE */
+
+#endif /* BOB_LEARN_EM_API_H */
diff --git a/bob/learn/misc/main.cpp b/bob/learn/misc/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..388a218c99b16c28b92ac46f90ac42607f3baec1
--- /dev/null
+++ b/bob/learn/misc/main.cpp
@@ -0,0 +1,89 @@
+/**
+ * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
+ * @date Fri Nov 21 12:39:21 CET 2014
+ *
+ * @brief Bindings to bob::learn::misc routines
+ */
+
+#ifdef NO_IMPORT_ARRAY
+#undef NO_IMPORT_ARRAY
+#endif
+#include "main.h"
+
+static PyMethodDef module_methods[] = {};
+
+
+PyDoc_STRVAR(module_docstr, "Bob EM based Machine Learning Routines");
+
+int PyBobLearnMisc_APIVersion = BOB_LEARN_MISC_API_VERSION;
+
+
+#if PY_VERSION_HEX >= 0x03000000
+static PyModuleDef module_definition = {
+  PyModuleDef_HEAD_INIT,
+  BOB_EXT_MODULE_NAME,
+  module_docstr,
+  -1,
+  module_methods,
+  0, 0, 0, 0
+};
+#endif
+
+static PyObject* create_module (void) {
+
+# if PY_VERSION_HEX >= 0x03000000
+  PyObject* module = PyModule_Create(&module_definition);
+# else
+  PyObject* module = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr);
+# endif
+  if (!module) return 0;
+  auto module_ = make_safe(module); ///< protects against early returns
+
+  if (PyModule_AddStringConstant(module, "__version__", BOB_EXT_MODULE_VERSION) < 0) return 0;
+  if (!init_BobLearnMiscGaussian(module)) return 0;
+
+  static void* PyBobLearnMisc_API[PyBobLearnMisc_API_pointers];
+
+  /* exhaustive list of C APIs */
+
+  /**************
+   * Versioning *
+   **************/
+
+  PyBobLearnMisc_API[PyBobLearnMisc_APIVersion_NUM] = (void *)&PyBobLearnMisc_APIVersion;
+
+
+#if PY_VERSION_HEX >= 0x02070000
+
+  /* defines the PyCapsule */
+
+  PyObject* c_api_object = PyCapsule_New((void *)PyBobLearnMisc_API,
+      BOB_EXT_MODULE_PREFIX "." BOB_EXT_MODULE_NAME "._C_API", 0);
+
+#else
+
+  PyObject* c_api_object = PyCObject_FromVoidPtr((void *)PyBobLearnMisc_API, 0);
+
+#endif
+
+  if (!c_api_object) return 0;
+
+  if (PyModule_AddObject(module, "_C_API", c_api_object) < 0) return 0;
+
+
+  /* imports bob.learn.misc's C-API dependencies */
+  if (import_bob_blitz() < 0) return 0;
+  if (import_bob_core_random() < 0) return 0;
+  if (import_bob_io_base() < 0) return 0;
+
+  Py_INCREF(module);
+  return module;
+
+}
+
+PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) {
+# if PY_VERSION_HEX >= 0x03000000
+  return
+# endif
+    create_module();
+}
diff --git a/bob/learn/misc/main.h b/bob/learn/misc/main.h
new file mode 100644
index 0000000000000000000000000000000000000000..bb40bec0d83308713311ab3ae30e47f4b6a2dffa
--- /dev/null
+++ b/bob/learn/misc/main.h
@@ -0,0 +1,72 @@
+/**
+ * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
+ * @date Fri Nov 21 10:31:25 CET 2014
+ *
+ * @brief Header file for bindings to bob::learn::em
+ */
+
+#ifndef BOB_LEARN_EM_MAIN_H
+#define BOB_LEARN_EM_MAIN_H
+
+#include <bob.blitz/cppapi.h>
+#include <bob.blitz/cleanup.h>
+#include <bob.core/random_api.h>
+#include <bob.io.base/api.h>
+#include <bob.extension/documentation.h>
+
+#define BOB_LEARN_EM_MODULE
+#include <bob.learn.misc/api.h>
+
+#include <bob.learn.misc/Gaussian.h>
+
+
+#if PY_VERSION_HEX >= 0x03000000
+#define PyInt_Check PyLong_Check
+#define PyInt_AS_LONG PyLong_AS_LONG
+#define PyString_Check PyUnicode_Check
+#define PyString_AS_STRING(x) PyBytes_AS_STRING(make_safe(PyUnicode_AsUTF8String(x)).get())
+#endif
+
+#define TRY try{
+
+#define CATCH(message,ret) }\
+  catch (std::exception& e) {\
+    PyErr_SetString(PyExc_RuntimeError, e.what());\
+    return ret;\
+  } \
+  catch (...) {\
+    PyErr_Format(PyExc_RuntimeError, "%s " message ": unknown exception caught", Py_TYPE(self)->tp_name);\
+    return ret;\
+  }
+
+#define CATCH_(message, ret) }\
+  catch (std::exception& e) {\
+    PyErr_SetString(PyExc_RuntimeError, e.what());\
+    return ret;\
+  } \
+  catch (...) {\
+    PyErr_Format(PyExc_RuntimeError, message ": unknown exception caught");\
+    return ret;\
+  }
+
+static inline char* c(const char* o){return const_cast<char*>(o);}  /* converts const char* to char* */
+
+/// inserts the given key, value pair into the given dictionaries
+static inline int insert_item_string(PyObject* dict, PyObject* entries, const char* key, Py_ssize_t value){
+  auto v = make_safe(Py_BuildValue("n", value));
+  if (PyDict_SetItemString(dict, key, v.get()) < 0) return -1;
+  return PyDict_SetItemString(entries, key, v.get());
+}
+
+// Gaussian
+typedef struct {
+  PyObject_HEAD
+  boost::shared_ptr<bob::learn::misc::Gaussian> cxx;
+} PyBobLearnMiscGaussianObject;
+
+extern PyTypeObject PyBobLearnMiscGaussian_Type;
+bool init_BobLearnMiscGaussian(PyObject* module);
+int PyBobLearnMiscGaussian_Check(PyObject* o);
+
+
+#endif // BOB_LEARN_EM_MAIN_H