Add pipe mechanism

Change-Id: I4207b33b1e4bab06ee632fd17be68542891caee3
diff --git a/dev/js/src/pipe.js b/dev/js/src/pipe.js
new file mode 100644
index 0000000..7b9afee
--- /dev/null
+++ b/dev/js/src/pipe.js
@@ -0,0 +1,76 @@
+/**
+ * Create a pipe object, that holds a list of services
+ * meant to transform the KQ passed before it's finally
+ * passed to the search engine.
+ *
+ * @author Nils Diewald
+ */
+define(function () {
+
+  "use strict";
+
+  const notNullRe = new RegExp("[a-zA-Z0-9]");
+
+  // Trim and check
+  function _notNull (service) {
+    service = service.trim();
+    if (service.match(notNullRe)) {
+      return service;
+    };
+    return null;
+  }
+  
+  return {
+
+    /**
+     * Constructor
+     */
+    create : function () {
+      let obj = Object.create(this);
+      obj._pipe = [];
+      return obj;
+    },
+
+    /**
+     * Append service to pipe.
+     */
+    append : function (service) {
+      service = _notNull(service);
+      if (service)
+        this._pipe.push(service);
+    },
+
+    /**
+     * Prepend service to pipe.
+     */
+    prepend : function (service) {
+      service = _notNull(service);
+      if (service)
+        this._pipe.unshift(service);
+    },
+
+    /**
+     * Remove service from the pipe.
+     */
+    remove : function (service) {
+      let i = this._pipe.indexOf(service);
+      if (i != -1) {
+        this._pipe.splice(i, 1);
+      };
+    },
+
+    /**
+     * The number of services in the pipe.
+     */
+    size : function () {
+      return this._pipe.length;
+    },
+
+    /**
+     * Return the pipe as a string.
+     */
+    toString : function () {
+      return this._pipe.join(',');
+    }
+  };
+});