ADD files for the new version
diff --git a/frontend/builders/builders.json b/frontend/builders/builders.json
new file mode 100644
index 0000000..8ec3ad4
--- /dev/null
+++ b/frontend/builders/builders.json
@@ -0,0 +1,9 @@
+{
+  "builders": {
+    "plugin": {
+      "class": "./plugin-builder",
+      "schema": "./plugin-builder/schema.json",
+      "description": "Plugin Builder"
+    }
+  }
+}
diff --git a/frontend/builders/package.json b/frontend/builders/package.json
new file mode 100644
index 0000000..f0b4a5b
--- /dev/null
+++ b/frontend/builders/package.json
@@ -0,0 +1,3 @@
+{
+  "builders": "builders.json"
+}
diff --git a/frontend/builders/plugin-builder/index.js b/frontend/builders/plugin-builder/index.js
new file mode 100644
index 0000000..3285a69
--- /dev/null
+++ b/frontend/builders/plugin-builder/index.js
@@ -0,0 +1,106 @@
+"use strict";
+/**
+ MIT License
+
+ Copyright (c) 2018 Alexey Zuev
+
+ Available from https://github.com/alexzuza/angular-plugin-architecture/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+const build_angular_1 = require("@angular-devkit/build-angular");
+const fs = require("fs");
+const operators_1 = require("rxjs/operators");
+class PluginBuilder extends build_angular_1.BrowserBuilder {
+    patchEntryPoint(contents) {
+        fs.writeFileSync(this.entryPointPath, contents);
+    }
+    buildWebpackConfig(root, projectRoot, host, options) {
+        const { pluginName, sharedLibs } = this.options;
+        if (!this.options.modulePath) {
+            throw Error('Please define modulePath!');
+        }
+        if (!pluginName) {
+            throw Error('Please provide pluginName!');
+        }
+        const config = super.buildWebpackConfig(root, projectRoot, host, options);
+        // Make sure we are producing a single bundle
+        delete config.entry.polyfills;
+        delete config.optimization.runtimeChunk;
+        delete config.optimization.splitChunks;
+        delete config.entry.styles;
+        config.externals = {
+            rxjs: 'rxjs',
+            '@angular/common/http': 'ng.http',
+            '@angular/core': 'ng.core',
+            '@angular/common': 'ng.common',
+            '@angular/forms': 'ng.forms',
+            '@angular/router': 'ng.router',
+            tslib: 'tslib',
+            'socket.io-client': 'socket.io-client',
+        };
+        if (sharedLibs) {
+            config.externals = [config.externals];
+            const sharedLibsArr = sharedLibs.split(',');
+            sharedLibsArr.forEach(sharedLibName => {
+                const factoryRegexp = new RegExp(`${sharedLibName}.ngfactory$`);
+                config.externals[0][sharedLibName] = sharedLibName; // define external for code
+                config.externals.push((context, request, callback) => {
+                    if (factoryRegexp.test(request)) {
+                        return callback(null, sharedLibName); // define external for factory
+                    }
+                    callback();
+                });
+            });
+        }
+        const ngCompilerPluginInstance = config.plugins.find(x => x.constructor && x.constructor.name === 'AngularCompilerPlugin');
+        if (ngCompilerPluginInstance) {
+            ngCompilerPluginInstance._entryModule = this.options.modulePath;
+        }
+        // preserve path to entry point
+        // so that we can clear use it within `run` method to clear that file
+        this.entryPointPath = config.entry.main[0];
+        const [modulePath, moduleName] = this.options.modulePath.split('#');
+        const factoryPath = `${modulePath.includes('.') ? modulePath : `${modulePath}/${modulePath}`}.ngfactory`;
+        const entryPointContents = `
+       export * from '${modulePath}';
+       export * from '${factoryPath}';
+       import { ${moduleName}NgFactory } from '${factoryPath}';
+       export default ${moduleName}NgFactory;
+    `;
+        this.patchEntryPoint(entryPointContents);
+        config.output.filename = `${pluginName}.js`;
+        config.output.library = pluginName;
+        config.output.libraryTarget = 'umd';
+        // workaround to support bundle on nodejs
+        config.output.globalObject = `(typeof self !== 'undefined' ? self : this)`;
+        return config;
+    }
+    run(builderConfig) {
+        this.options = builderConfig.options;
+        // I don't want to write it in my scripts every time so I keep it here
+        builderConfig.options.deleteOutputPath = false;
+        return super.run(builderConfig).pipe(operators_1.tap(() => {
+            // clear entry point so our main.ts is always empty
+            this.patchEntryPoint('');
+        }));
+    }
+}
+exports.default = PluginBuilder;
diff --git a/frontend/builders/plugin-builder/index.ts b/frontend/builders/plugin-builder/index.ts
new file mode 100644
index 0000000..1483821
--- /dev/null
+++ b/frontend/builders/plugin-builder/index.ts
@@ -0,0 +1,162 @@
+/**
+ MIT License
+
+ Copyright (c) 2018 Alexey Zuev
+
+ Available from https://github.com/alexzuza/angular-plugin-architecture/
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+import {
+  BrowserBuilder,
+  NormalizedBrowserBuilderSchema
+} from '@angular-devkit/build-angular';
+import { Path, virtualFs } from '@angular-devkit/core';
+import * as fs from 'fs';
+import { Observable } from 'rxjs';
+
+import { BuilderConfiguration, BuildEvent } from '@angular-devkit/architect';
+import { tap } from 'rxjs/operators';
+
+interface PluginBuilderSchema extends NormalizedBrowserBuilderSchema {
+  /**
+   * A string of the form `path/to/file#exportName` that acts as a path to include to bundle
+   */
+  modulePath: string;
+
+  /**
+   * A name of compiled bundle
+   */
+  pluginName: string;
+
+  /**
+   * A comma-delimited list of shared lib names used by current plugin
+   */
+  sharedLibs: string;
+}
+export default class PluginBuilder extends BrowserBuilder {
+  private options: PluginBuilderSchema;
+
+  private entryPointPath: string;
+
+  patchEntryPoint(contents: string) {
+    fs.writeFileSync(this.entryPointPath, contents);
+  }
+
+  buildWebpackConfig(
+    root: Path,
+    projectRoot: Path,
+    host: virtualFs.Host<fs.Stats>,
+    options: PluginBuilderSchema
+  ) {
+    const { pluginName, sharedLibs } = this.options;
+
+    if (!this.options.modulePath) {
+      throw Error('Please define modulePath!');
+    }
+
+    if (!pluginName) {
+      throw Error('Please provide pluginName!');
+    }
+
+    const config = super.buildWebpackConfig(root, projectRoot, host, options);
+
+    // Make sure we are producing a single bundle
+    delete config.entry.polyfills;
+    delete config.optimization.runtimeChunk;
+    delete config.optimization.splitChunks;
+    delete config.entry.styles;
+
+    config.externals = {
+      rxjs: 'rxjs',
+      '@angular/common/http': 'ng.http',
+      '@angular/core': 'ng.core',
+      '@angular/common': 'ng.common',
+      '@angular/forms': 'ng.forms',
+      '@angular/router': 'ng.router',
+      tslib: 'tslib',
+      'socket.io-client': 'socket.io-client',
+      // socketService: 'socketService'
+      // put here other common dependencies
+    };
+
+    if (sharedLibs) {
+      config.externals = [config.externals];
+      const sharedLibsArr = sharedLibs.split(',');
+      sharedLibsArr.forEach(sharedLibName => {
+        const factoryRegexp = new RegExp(`${sharedLibName}.ngfactory$`);
+        config.externals[0][sharedLibName] = sharedLibName; // define external for code
+        config.externals.push((context, request, callback) => {
+          if (factoryRegexp.test(request)) {
+            return callback(null, sharedLibName); // define external for factory
+          }
+          callback();
+        });
+      });
+    }
+
+    const ngCompilerPluginInstance = config.plugins.find(
+      x => x.constructor && x.constructor.name === 'AngularCompilerPlugin'
+    );
+    if (ngCompilerPluginInstance) {
+      ngCompilerPluginInstance._entryModule = this.options.modulePath;
+    }
+
+    // preserve path to entry point
+    // so that we can clear use it within `run` method to clear that file
+    this.entryPointPath = config.entry.main[0];
+
+    const [modulePath, moduleName] = this.options.modulePath.split('#');
+
+    const factoryPath = `${
+      modulePath.includes('.') ? modulePath : `${modulePath}/${modulePath}`
+    }.ngfactory`;
+    const entryPointContents = `
+       export * from '${modulePath}';
+       export * from '${factoryPath}';
+       import { ${moduleName}NgFactory } from '${factoryPath}';
+       export default ${moduleName}NgFactory;
+    `;
+    this.patchEntryPoint(entryPointContents);
+
+    config.output.filename = `${pluginName}.js`;
+    config.output.library = pluginName;
+    config.output.libraryTarget = 'umd';
+    // workaround to support bundle on nodejs
+    config.output.globalObject = `(typeof self !== 'undefined' ? self : this)`;
+
+    return config;
+  }
+
+  run(
+    builderConfig: BuilderConfiguration<PluginBuilderSchema>
+  ): Observable<BuildEvent> {
+    this.options = builderConfig.options;
+    // I don't want to write it in my scripts every time so I keep it here
+    builderConfig.options.deleteOutputPath = false;
+
+    return super.run(builderConfig).pipe(
+      tap(() => {
+        // clear entry point so our main.ts is always empty
+        this.patchEntryPoint('');
+      })
+    );
+  }
+}
diff --git a/frontend/builders/plugin-builder/schema.json b/frontend/builders/plugin-builder/schema.json
new file mode 100644
index 0000000..c9bdc72
--- /dev/null
+++ b/frontend/builders/plugin-builder/schema.json
@@ -0,0 +1,466 @@
+{
+  "$schema": "http://json-schema.org/schema",
+  "title": "Webpack browser schema for Build Facade.",
+  "description": "Browser target options",
+  "type": "object",
+  "properties": {
+    "modulePath": {
+      "type": "string",
+      "description": "Path to module like loadChildren",
+      "default": ""
+    },
+    "pluginName": {
+      "type": "string",
+      "description": "Name of bundled plugin",
+      "default": ""
+    },
+    "sharedLibs": {
+      "type": "string",
+      "description": "A comma-delimited list of shared lib names used by current plugin",
+      "default": ""
+    },
+    "assets": {
+      "type": "array",
+      "description": "List of static application assets.",
+      "default": [],
+      "items": {
+        "$ref": "#/definitions/assetPattern"
+      }
+    },
+    "main": {
+      "type": "string",
+      "description": "The full path for the main entry point to the app, relative to the current workspace.",
+      "$valueDescription": "fileName"
+    },
+    "polyfills": {
+      "type": "string",
+      "description": "The full path for the polyfills file, relative to the current workspace."
+    },
+    "tsConfig": {
+      "type": "string",
+      "description": "The full path for the TypeScript configuration file, relative to the current workspace."
+    },
+    "scripts": {
+      "description": "Global scripts to be included in the build.",
+      "type": "array",
+      "default": [],
+      "items": {
+        "$ref": "#/definitions/extraEntryPoint"
+      }
+    },
+    "styles": {
+      "description": "Global styles to be included in the build.",
+      "type": "array",
+      "default": [],
+      "items": {
+        "$ref": "#/definitions/extraEntryPoint"
+      }
+    },
+    "stylePreprocessorOptions": {
+      "description": "Options to pass to style preprocessors.",
+      "type": "object",
+      "properties": {
+        "includePaths": {
+          "description": "Paths to include. Paths will be resolved to project root.",
+          "type": "array",
+          "items": {
+            "type": "string"
+          },
+          "default": []
+        }
+      },
+      "additionalProperties": false
+    },
+    "optimization": {
+      "description": "Enables optimization of the build output.",
+      "oneOf": [
+        {
+          "type": "object",
+          "properties": {
+            "scripts": {
+              "type": "boolean",
+              "description": "Enables optimization of the scripts output.",
+              "default": true
+            },
+            "styles": {
+              "type": "boolean",
+              "description": "Enables optimization of the styles output.",
+              "default": true
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "type": "boolean"
+        }
+      ]
+    },
+    "fileReplacements": {
+      "description": "Replace files with other files in the build.",
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/fileReplacement"
+      },
+      "default": []
+    },
+    "outputPath": {
+      "type": "string",
+      "description": "The full path for the new output directory, relative to the current workspace.\n\nBy default, writes output to a folder named dist/ in the current project."
+    },
+    "resourcesOutputPath": {
+      "type": "string",
+      "description": "The path where style resources will be placed, relative to outputPath.",
+      "default": ""
+    },
+    "aot": {
+      "type": "boolean",
+      "description": "Build using Ahead of Time compilation.",
+      "default": false
+    },
+    "sourceMap": {
+      "description": "Output sourcemaps.",
+      "default": true,
+      "oneOf": [
+        {
+          "type": "object",
+          "properties": {
+            "scripts": {
+              "type": "boolean",
+              "description": "Output sourcemaps for all scripts.",
+              "default": true
+            },
+            "styles": {
+              "type": "boolean",
+              "description": "Output sourcemaps for all styles.",
+              "default": true
+            },
+            "hidden": {
+              "type": "boolean",
+              "description": "Output sourcemaps used for error reporting tools.",
+              "default": false
+            },
+            "vendor": {
+              "type": "boolean",
+              "description": "Resolve vendor packages sourcemaps.",
+              "default": false
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "type": "boolean"
+        }
+      ]
+    },
+    "vendorSourceMap": {
+      "type": "boolean",
+      "description": "Resolve vendor packages sourcemaps.",
+      "x-deprecated": true,
+      "default": false
+    },
+    "evalSourceMap": {
+      "type": "boolean",
+      "description": "Output in-file eval sourcemaps.",
+      "default": false,
+      "x-deprecated": true
+    },
+    "vendorChunk": {
+      "type": "boolean",
+      "description": "Use a separate bundle containing only vendor libraries.",
+      "default": true
+    },
+    "commonChunk": {
+      "type": "boolean",
+      "description": "Use a separate bundle containing code used across multiple bundles.",
+      "default": true
+    },
+    "baseHref": {
+      "type": "string",
+      "description": "Base url for the application being built."
+    },
+    "deployUrl": {
+      "type": "string",
+      "description": "URL where files will be deployed."
+    },
+    "verbose": {
+      "type": "boolean",
+      "description": "Adds more details to output logging.",
+      "default": false
+    },
+    "progress": {
+      "type": "boolean",
+      "description": "Log progress to the console while building."
+    },
+    "i18nFile": {
+      "type": "string",
+      "description": "Localization file to use for i18n."
+    },
+    "i18nFormat": {
+      "type": "string",
+      "description": "Format of the localization file specified with --i18n-file."
+    },
+    "i18nLocale": {
+      "type": "string",
+      "description": "Locale to use for i18n."
+    },
+    "i18nMissingTranslation": {
+      "type": "string",
+      "description": "How to handle missing translations for i18n."
+    },
+    "extractCss": {
+      "type": "boolean",
+      "description": "Extract css from global styles into css files instead of js ones.",
+      "default": false
+    },
+    "watch": {
+      "type": "boolean",
+      "description": "Run build when files change.",
+      "default": false
+    },
+    "outputHashing": {
+      "type": "string",
+      "description": "Define the output filename cache-busting hashing mode.",
+      "default": "none",
+      "enum": ["none", "all", "media", "bundles"]
+    },
+    "poll": {
+      "type": "number",
+      "description": "Enable and define the file watching poll time period in milliseconds."
+    },
+    "deleteOutputPath": {
+      "type": "boolean",
+      "description": "Delete the output path before building.",
+      "default": true
+    },
+    "preserveSymlinks": {
+      "type": "boolean",
+      "description": "Do not use the real path when resolving modules.",
+      "default": false
+    },
+    "extractLicenses": {
+      "type": "boolean",
+      "description": "Extract all licenses in a separate file.",
+      "default": false
+    },
+    "showCircularDependencies": {
+      "type": "boolean",
+      "description": "Show circular dependency warnings on builds.",
+      "default": true
+    },
+    "buildOptimizer": {
+      "type": "boolean",
+      "description": "Enables '@angular-devkit/build-optimizer' optimizations when using the 'aot' option.",
+      "default": false
+    },
+    "namedChunks": {
+      "type": "boolean",
+      "description": "Use file name for lazy loaded chunks.",
+      "default": true
+    },
+    "subresourceIntegrity": {
+      "type": "boolean",
+      "description": "Enables the use of subresource integrity validation.",
+      "default": false
+    },
+    "serviceWorker": {
+      "type": "boolean",
+      "description": "Generates a service worker config for production builds.",
+      "default": false
+    },
+    "ngswConfigPath": {
+      "type": "string",
+      "description": "Path to ngsw-config.json."
+    },
+    "skipAppShell": {
+      "type": "boolean",
+      "description": "Flag to prevent building an app shell.",
+      "default": false,
+      "x-deprecated": true
+    },
+    "index": {
+      "type": "string",
+      "description": "The name of the index HTML file."
+    },
+    "statsJson": {
+      "type": "boolean",
+      "description": "Generates a 'stats.json' file which can be analyzed using tools such as 'webpack-bundle-analyzer'.",
+      "default": false
+    },
+    "forkTypeChecker": {
+      "type": "boolean",
+      "description": "Run the TypeScript type checker in a forked process.",
+      "default": true
+    },
+    "lazyModules": {
+      "description": "List of additional NgModule files that will be lazy loaded. Lazy router modules will be discovered automatically.",
+      "type": "array",
+      "items": {
+        "type": "string"
+      },
+      "default": []
+    },
+    "budgets": {
+      "description": "Budget thresholds to ensure parts of your application stay within boundaries which you set.",
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/budget"
+      },
+      "default": []
+    },
+    "profile": {
+      "type": "boolean",
+      "description": "Output profile events for Chrome profiler.",
+      "default": false
+    },
+    "es5BrowserSupport": {
+      "description": "Enables conditionally loaded ES2015 polyfills.",
+      "type": "boolean",
+      "default": false
+    },
+    "rebaseRootRelativeCssUrls": {
+      "description": "Change root relative URLs in stylesheets to include base HREF and deploy URL. Use only for compatibility and transition. The behavior of this option is non-standard and will be removed in the next major release.",
+      "type": "boolean",
+      "default": false,
+      "x-deprecated": true
+    }
+  },
+  "additionalProperties": false,
+  "required": ["outputPath", "index", "main", "tsConfig"],
+  "definitions": {
+    "assetPattern": {
+      "oneOf": [
+        {
+          "type": "object",
+          "properties": {
+            "glob": {
+              "type": "string",
+              "description": "The pattern to match."
+            },
+            "input": {
+              "type": "string",
+              "description": "The input directory path in which to apply 'glob'. Defaults to the project root."
+            },
+            "ignore": {
+              "description": "An array of globs to ignore.",
+              "type": "array",
+              "items": {
+                "type": "string"
+              }
+            },
+            "output": {
+              "type": "string",
+              "description": "Absolute path within the output."
+            }
+          },
+          "additionalProperties": false,
+          "required": ["glob", "input", "output"]
+        },
+        {
+          "type": "string"
+        }
+      ]
+    },
+    "fileReplacement": {
+      "oneOf": [
+        {
+          "type": "object",
+          "properties": {
+            "src": {
+              "type": "string"
+            },
+            "replaceWith": {
+              "type": "string"
+            }
+          },
+          "additionalProperties": false,
+          "required": ["src", "replaceWith"]
+        },
+        {
+          "type": "object",
+          "properties": {
+            "replace": {
+              "type": "string"
+            },
+            "with": {
+              "type": "string"
+            }
+          },
+          "additionalProperties": false,
+          "required": ["replace", "with"]
+        }
+      ]
+    },
+    "extraEntryPoint": {
+      "oneOf": [
+        {
+          "type": "object",
+          "properties": {
+            "input": {
+              "type": "string",
+              "description": "The file to include."
+            },
+            "bundleName": {
+              "type": "string",
+              "description": "The bundle name for this extra entry point."
+            },
+            "lazy": {
+              "type": "boolean",
+              "description": "If the bundle will be lazy loaded.",
+              "default": false
+            }
+          },
+          "additionalProperties": false,
+          "required": ["input"]
+        },
+        {
+          "type": "string",
+          "description": "The file to include."
+        }
+      ]
+    },
+    "budget": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "type": "string",
+          "description": "The type of budget.",
+          "enum": ["all", "allScript", "any", "anyScript", "bundle", "initial"]
+        },
+        "name": {
+          "type": "string",
+          "description": "The name of the bundle."
+        },
+        "baseline": {
+          "type": "string",
+          "description": "The baseline size for comparison."
+        },
+        "maximumWarning": {
+          "type": "string",
+          "description": "The maximum threshold for warning relative to the baseline."
+        },
+        "maximumError": {
+          "type": "string",
+          "description": "The maximum threshold for error relative to the baseline."
+        },
+        "minimumWarning": {
+          "type": "string",
+          "description": "The minimum threshold for warning relative to the baseline."
+        },
+        "minimumError": {
+          "type": "string",
+          "description": "The minimum threshold for error relative to the baseline."
+        },
+        "warning": {
+          "type": "string",
+          "description": "The threshold for warning relative to the baseline (min & max)."
+        },
+        "error": {
+          "type": "string",
+          "description": "The threshold for error relative to the baseline (min & max)."
+        }
+      },
+      "additionalProperties": false,
+      "required": ["type"]
+    }
+  }
+}
diff --git a/frontend/builders/tsconfig.builders.json b/frontend/builders/tsconfig.builders.json
new file mode 100644
index 0000000..1088f22
--- /dev/null
+++ b/frontend/builders/tsconfig.builders.json
@@ -0,0 +1,13 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "module": "commonjs",
+    "outDir": "./plugin-builder",
+    "importHelpers": false,
+    "sourceMap": false,
+    "target": "es6"
+  },
+  "files": [
+    "./plugin-builder/index.ts"
+  ]
+}