Merge branch 'release' into 'master'

ReleaseVersion-0.1.0

See merge request agens_tech/agensbrowser-nodejs!33
diff --git a/backend/package-lock.json b/backend/package-lock.json
index 384407f..509a6d5 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -21,6 +21,18 @@
         "pg": ">= 6.1.2"
       }
     },
+    "ansi-colors": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true
+    },
     "ansi-styles": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
@@ -29,11 +41,48 @@
         "color-convert": "^1.9.0"
       }
     },
+    "anymatch": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+      "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+      "dev": true,
+      "requires": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
     "array-flatten": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
       "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
     },
+    "array.prototype.map": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz",
+      "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.17.0-next.1",
+        "es-array-method-boxes-properly": "^1.0.0",
+        "is-string": "^1.0.4"
+      }
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "dev": true
+    },
     "balanced-match": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -47,6 +96,12 @@
         "safe-buffer": "5.1.2"
       }
     },
+    "binary-extensions": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
+      "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
+      "dev": true
+    },
     "body-parser": {
       "version": "1.18.3",
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
@@ -73,6 +128,21 @@
         "concat-map": "0.0.1"
       }
     },
+    "braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "requires": {
+        "fill-range": "^7.0.1"
+      }
+    },
+    "browser-stdout": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+      "dev": true
+    },
     "buffer-writer": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
@@ -83,6 +153,12 @@
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
       "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
     },
+    "camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true
+    },
     "chalk": {
       "version": "2.4.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -93,6 +169,61 @@
         "supports-color": "^5.3.0"
       }
     },
+    "chokidar": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
+      "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
+      "dev": true,
+      "requires": {
+        "anymatch": "~3.1.1",
+        "braces": "~3.0.2",
+        "fsevents": "~2.1.2",
+        "glob-parent": "~5.1.0",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.3.0"
+      }
+    },
+    "cliui": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+      "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+      "dev": true,
+      "requires": {
+        "string-width": "^3.1.0",
+        "strip-ansi": "^5.2.0",
+        "wrap-ansi": "^5.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
     "color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -106,6 +237,21 @@
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
     },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
+    "component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true
+    },
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -140,6 +286,18 @@
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
     },
+    "cookiejar": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz",
+      "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==",
+      "dev": true
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
     "cross-spawn": {
       "version": "6.0.5",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@@ -167,6 +325,12 @@
         "ms": "2.0.0"
       }
     },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true
+    },
     "define-properties": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -175,6 +339,12 @@
         "object-keys": "^1.0.12"
       }
     },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true
+    },
     "depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -185,11 +355,23 @@
       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
     },
+    "diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "dev": true
+    },
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
+    "emoji-regex": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+      "dev": true
+    },
     "encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -221,6 +403,35 @@
         "string.prototype.trimstart": "^1.0.1"
       }
     },
+    "es-array-method-boxes-properly": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
+      "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
+      "dev": true
+    },
+    "es-get-iterator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz",
+      "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==",
+      "dev": true,
+      "requires": {
+        "es-abstract": "^1.17.4",
+        "has-symbols": "^1.0.1",
+        "is-arguments": "^1.0.4",
+        "is-map": "^2.0.1",
+        "is-set": "^2.0.1",
+        "is-string": "^1.0.5",
+        "isarray": "^2.0.5"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "2.0.5",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+          "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+          "dev": true
+        }
+      }
+    },
     "es-to-primitive": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
@@ -241,6 +452,12 @@
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true
+    },
     "etag": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
@@ -317,6 +534,21 @@
         }
       }
     },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "requires": {
+        "to-regex-range": "^5.0.1"
+      }
+    },
     "finalhandler": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
@@ -331,6 +563,42 @@
         "unpipe": "~1.0.0"
       }
     },
+    "find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "requires": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      }
+    },
+    "flat": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz",
+      "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==",
+      "dev": true,
+      "requires": {
+        "is-buffer": "~2.0.3"
+      }
+    },
+    "form-data": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+      "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+      "dev": true,
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      }
+    },
+    "formidable": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
+      "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==",
+      "dev": true
+    },
     "forwarded": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@@ -341,16 +609,64 @@
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
       "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
     },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+      "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+      "dev": true,
+      "optional": true
+    },
     "function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
     },
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true
+    },
+    "glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "glob-parent": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+      "dev": true,
+      "requires": {
+        "is-glob": "^4.0.1"
+      }
+    },
     "graceful-fs": {
       "version": "4.2.4",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
       "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
     },
+    "growl": {
+      "version": "1.10.5",
+      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+      "dev": true
+    },
     "has": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -369,6 +685,12 @@
       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
       "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
     },
+    "he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true
+    },
     "hosted-git-info": {
       "version": "2.8.8",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
@@ -393,6 +715,16 @@
         "safer-buffer": ">= 2.1.2 < 3"
       }
     },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
     "inherits": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
@@ -403,11 +735,32 @@
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
       "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
     },
+    "is-arguments": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
+      "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
+      "dev": true
+    },
     "is-arrayish": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
       "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
     },
+    "is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "requires": {
+        "binary-extensions": "^2.0.0"
+      }
+    },
+    "is-buffer": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
+      "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
+      "dev": true
+    },
     "is-callable": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz",
@@ -418,6 +771,45 @@
       "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
       "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g=="
     },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true
+    },
+    "is-glob": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-map": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz",
+      "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==",
+      "dev": true
+    },
+    "is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true
+    },
+    "is-plain-obj": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+      "dev": true
+    },
     "is-regex": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz",
@@ -426,6 +818,18 @@
         "has-symbols": "^1.0.1"
       }
     },
+    "is-set": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz",
+      "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==",
+      "dev": true
+    },
+    "is-string": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
+      "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
+      "dev": true
+    },
     "is-symbol": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
@@ -434,11 +838,43 @@
         "has-symbols": "^1.0.1"
       }
     },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
     "isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
       "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
     },
+    "iterate-iterator": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz",
+      "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==",
+      "dev": true
+    },
+    "iterate-value": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz",
+      "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==",
+      "dev": true,
+      "requires": {
+        "es-get-iterator": "^1.0.2",
+        "iterate-iterator": "^1.0.1"
+      }
+    },
+    "js-yaml": {
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+      "dev": true,
+      "requires": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      }
+    },
     "json-parse-better-errors": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@@ -455,11 +891,29 @@
         "strip-bom": "^3.0.0"
       }
     },
+    "locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "requires": {
+        "p-locate": "^4.1.0"
+      }
+    },
     "lodash": {
       "version": "4.17.19",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
       "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
     },
+    "log-symbols": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
+      "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.4.2"
+      }
+    },
     "media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -506,6 +960,80 @@
         "brace-expansion": "^1.1.7"
       }
     },
+    "mocha": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.1.0.tgz",
+      "integrity": "sha512-sI0gaI1I/jPVu3KFpnveWGadfe3JNBAENqgTUPgLZAUppu725zS2mrVztzAgIR8DUscuS4doEBTx9LATC+HSeA==",
+      "dev": true,
+      "requires": {
+        "ansi-colors": "4.1.1",
+        "browser-stdout": "1.3.1",
+        "chokidar": "3.3.1",
+        "debug": "3.2.6",
+        "diff": "4.0.2",
+        "escape-string-regexp": "1.0.5",
+        "find-up": "4.1.0",
+        "glob": "7.1.6",
+        "growl": "1.10.5",
+        "he": "1.2.0",
+        "js-yaml": "3.13.1",
+        "log-symbols": "3.0.0",
+        "minimatch": "3.0.4",
+        "ms": "2.1.2",
+        "object.assign": "4.1.0",
+        "promise.allsettled": "1.0.2",
+        "serialize-javascript": "4.0.0",
+        "strip-json-comments": "3.0.1",
+        "supports-color": "7.1.0",
+        "which": "2.0.2",
+        "wide-align": "1.1.3",
+        "workerpool": "6.0.0",
+        "yargs": "13.3.2",
+        "yargs-parser": "13.1.2",
+        "yargs-unparser": "1.6.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.6",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "which": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+          "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+          "dev": true,
+          "requires": {
+            "isexe": "^2.0.0"
+          }
+        }
+      }
+    },
     "morgan": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
@@ -544,6 +1072,12 @@
         "validate-npm-package-license": "^3.0.1"
       }
     },
+    "normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true
+    },
     "npm-run-all": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
@@ -560,6 +1094,12 @@
         "string.prototype.padend": "^3.0.0"
       }
     },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
     "object-inspect": {
       "version": "1.8.0",
       "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
@@ -594,6 +1134,39 @@
       "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
       "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
     },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "requires": {
+        "p-try": "^2.0.0"
+      }
+    },
+    "p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "requires": {
+        "p-limit": "^2.2.0"
+      }
+    },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true
+    },
     "packet-reader": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
@@ -613,6 +1186,18 @@
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
       "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
     },
+    "path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
     "path-key": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
@@ -696,6 +1281,12 @@
         "split": "^1.0.0"
       }
     },
+    "picomatch": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+      "dev": true
+    },
     "pidtree": {
       "version": "0.3.1",
       "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
@@ -729,6 +1320,25 @@
         "xtend": "^4.0.0"
       }
     },
+    "process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true
+    },
+    "promise.allsettled": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz",
+      "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==",
+      "dev": true,
+      "requires": {
+        "array.prototype.map": "^1.0.1",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.17.0-next.1",
+        "function-bind": "^1.1.1",
+        "iterate-value": "^1.0.0"
+      }
+    },
     "proxy-addr": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
@@ -748,6 +1358,15 @@
       "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
       "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
     },
+    "randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
     "range-parser": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -774,6 +1393,42 @@
         "path-type": "^3.0.0"
       }
     },
+    "readable-stream": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "dev": true,
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "readdirp": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
+      "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
+      "dev": true,
+      "requires": {
+        "picomatch": "^2.0.7"
+      }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "dev": true
+    },
     "resolve": {
       "version": "1.17.0",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
@@ -817,6 +1472,15 @@
         "statuses": "~1.4.0"
       }
     },
+    "serialize-javascript": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+      "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
+      "dev": true,
+      "requires": {
+        "randombytes": "^2.1.0"
+      }
+    },
     "serve-static": {
       "version": "1.13.2",
       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
@@ -828,6 +1492,12 @@
         "send": "0.16.2"
       }
     },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+      "dev": true
+    },
     "setprototypeof": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
@@ -887,11 +1557,27 @@
         "through": "2"
       }
     },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
     "statuses": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
       "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
     },
+    "string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      }
+    },
     "string.prototype.padend": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz",
@@ -919,11 +1605,89 @@
         "es-abstract": "^1.17.5"
       }
     },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^3.0.0"
+      }
+    },
     "strip-bom": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
       "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
     },
+    "strip-json-comments": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
+      "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
+      "dev": true
+    },
+    "superagent": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz",
+      "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==",
+      "dev": true,
+      "requires": {
+        "component-emitter": "^1.2.0",
+        "cookiejar": "^2.1.0",
+        "debug": "^3.1.0",
+        "extend": "^3.0.0",
+        "form-data": "^2.3.1",
+        "formidable": "^1.2.0",
+        "methods": "^1.1.1",
+        "mime": "^1.4.1",
+        "qs": "^6.5.1",
+        "readable-stream": "^2.3.5"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.6",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        }
+      }
+    },
+    "supertest": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/supertest/-/supertest-4.0.2.tgz",
+      "integrity": "sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ==",
+      "dev": true,
+      "requires": {
+        "methods": "^1.1.2",
+        "superagent": "^3.8.3"
+      }
+    },
+    "supertest-session": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/supertest-session/-/supertest-session-4.0.0.tgz",
+      "integrity": "sha512-9d7KAL+K9hnnicov7USv/Nu1tSl40qSrOsB8zZHOEtfEzHaAoID6tbl1NeCVUg7SJreJMlNn+KJ88V7FW8gD6Q==",
+      "dev": true,
+      "requires": {
+        "object-assign": "^4.0.1"
+      }
+    },
     "supports-color": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -937,6 +1701,15 @@
       "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
       "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
     },
+    "to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "requires": {
+        "is-number": "^7.0.0"
+      }
+    },
     "type-is": {
       "version": "1.6.18",
       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -959,6 +1732,12 @@
       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
       "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
     },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
     "utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -986,10 +1765,276 @@
         "isexe": "^2.0.0"
       }
     },
+    "which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+      "dev": true
+    },
+    "wide-align": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.2 || 2"
+      }
+    },
+    "workerpool": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz",
+      "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==",
+      "dev": true
+    },
+    "wrap-ansi": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+      "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.0",
+        "string-width": "^3.0.0",
+        "strip-ansi": "^5.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
     "xtend": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
       "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
+    },
+    "y18n": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+      "dev": true
+    },
+    "yargs": {
+      "version": "13.3.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+      "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+      "dev": true,
+      "requires": {
+        "cliui": "^5.0.0",
+        "find-up": "^3.0.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^3.0.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^13.1.2"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "find-up": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^3.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^3.0.0",
+            "path-exists": "^3.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.0.0"
+          }
+        },
+        "path-exists": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
+    "yargs-parser": {
+      "version": "13.1.2",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+      "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      }
+    },
+    "yargs-unparser": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.1.tgz",
+      "integrity": "sha512-qZV14lK9MWsGCmcr7u5oXGH0dbGqZAIxTDrWXZDo5zUr6b6iUmelNKO6x6R1dQT24AH3LgRxJpr8meWy2unolA==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.3.1",
+        "decamelize": "^1.2.0",
+        "flat": "^4.1.0",
+        "is-plain-obj": "^1.1.0",
+        "yargs": "^14.2.3"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "find-up": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^3.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^3.0.0",
+            "path-exists": "^3.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.0.0"
+          }
+        },
+        "path-exists": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        },
+        "yargs": {
+          "version": "14.2.3",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz",
+          "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
+          "dev": true,
+          "requires": {
+            "cliui": "^5.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^3.0.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^3.0.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^15.0.1"
+          }
+        },
+        "yargs-parser": {
+          "version": "15.0.1",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz",
+          "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
+          "dev": true,
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
     }
   }
 }
diff --git a/backend/package.json b/backend/package.json
index 32ea72f..34aa732 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,19 +1,28 @@
 {
-  "name": "agensbrowser",
-  "version": "0.0.1",
-  "private": true,
-  "scripts": {
-    "start": "node ./server/bin/www"
-  },
-  "dependencies": {
-    "agensgraph": "git+https://github.com/bitnine-oss/agensgraph-nodejs.git",
-    "cookie-parser": "~1.4.4",
-    "debug": "~2.6.9",
-    "express": "~4.16.1",
-    "express-session": "^1.17.1",
-    "morgan": "~1.9.1",
-    "npm-run-all": "^4.1.5",
-    "pegjs": "^0.10.0",
-    "pg": "^8.3.0"
-  }
+    "name": "agensbrowser",
+    "version": "0.0.1",
+    "private": true,
+    "scripts": {
+        "test": "mocha",
+        "test:connector": "mocha ./test/connector.api.test.js",
+        "test:cypher": "mocha ./test/cypher.api.test.js",
+        "test:query": "mocha ./test/cypher.service.test.js",
+        "start": "node ./server/bin/www"
+    },
+    "dependencies": {
+        "agensgraph": "git+https://github.com/bitnine-oss/agensgraph-nodejs.git",
+        "cookie-parser": "~1.4.4",
+        "debug": "~2.6.9",
+        "express": "~4.16.1",
+        "express-session": "^1.17.1",
+        "morgan": "~1.9.1",
+        "npm-run-all": "^4.1.5",
+        "pegjs": "^0.10.0",
+        "pg": "^8.3.0"
+    },
+    "devDependencies": {
+        "mocha": "^8.1.0",
+        "supertest": "^4.0.2",
+        "supertest-session": "^4.0.0"
+    }
 }
diff --git a/backend/server/api/cypher/cypherController.js b/backend/server/api/cypher/cypherController.js
deleted file mode 100644
index bb64a82..0000000
--- a/backend/server/api/cypher/cypherController.js
+++ /dev/null
@@ -1,63 +0,0 @@
-let express = require('express');
-let ag = require('agensgraph');
-
-let router = express.Router();
-
-router.post('/', function (req, res, next) {
-    if (!req.session.client) {
-        res.status(500);
-    } else {
-        let cmd = req.body.cmd;
-
-        const client = new ag.Client(req.session.client);
-        client.connect();
-        client.query(`set graph_path=${req.session.client.graph}`);
-        client.query(cmd, (err, resultSet) => {
-            let rows = resultSet.rows, columns = resultSet.fields.map((d) => d.name);
-
-            let convertedRows = rows.map((row) => {
-                let convetedObject = {};
-                for (let k in row) {
-                    if (row[k].hasOwnProperty('start')) {
-                        convetedObject[k] = convertEdge(row[k]);
-                    } else if (row[k].hasOwnProperty('id')) {
-                        convetedObject[k] = convertVertex(row[k]);
-                    } else {
-                        convetedObject[k] = row[k];
-                    }
-                }
-                return convetedObject;
-            });
-
-            result = convertedRows;
-            res.status(200).json({
-                message: 'OK',
-                data: {
-                    rows: convertedRows,
-                    columns: columns,
-                },
-            });
-            client.end();
-        });
-    }
-});
-
-function convertEdge({ label, id, start, end, props }) {
-    return {
-        label: label,
-        id: `${id.oid}.${id.id}`,
-        start: `${start.oid}.${start.id}`,
-        end: `${end.oid}.${end.id}`,
-        properties: props,
-    };
-}
-
-function convertVertex({ label, id, props }) {
-    return {
-        label: label,
-        id: `${id.oid}.${id.id}`,
-        properties: props,
-    };
-}
-
-module.exports = router;
diff --git a/backend/server/api/database/databaseController.js b/backend/server/api/database/databaseController.js
deleted file mode 100644
index ed076d9..0000000
--- a/backend/server/api/database/databaseController.js
+++ /dev/null
@@ -1,60 +0,0 @@
-let express = require('express');
-let router = express.Router();
-
-router.get('/', (req, res, next) => {
-    let message, data;
-    if(!req.session.client) {
-        message = 'Not Connected Database';
-        data = {};
-    } else {
-        message = 'Connected Database';
-        data = req.session.client;
-    }
-
-    res.status(200).send({
-        message: message,
-        data: data
-    }).end();
-})
-
-router.post('/connect', (req, res, next) => {
-    let connInfo = req.body;
-    if(!req.session.client) {
-        try {
-            req.session.client = connInfo;
-            res.status(200).send({
-                message: 'Successful Connected',
-                data: connInfo
-            }).end();
-        } catch (e) {
-            console.log(e);
-            res.status(500).send({
-                message: 'Failed Connect',
-                data: {
-                    'Error': e
-                }
-            }).end();
-        }
-    } else {
-        res.status(200).json({
-            message: 'Already Connected',
-            data: {
-                host: req.session.client.host,
-                port: req.session.client.port,
-                database: req.session.client.database
-            }
-        }).end();
-    }
-});
-
-router.get('/disconnect', (req, res, next) => {
-    if(!!req.session.client) {
-        req.session.client = null;
-        res.status(200).send('disconnect database').end();
-    } else {
-
-    }
-    res.send('disconnect database');
-});
-
-module.exports = router;
diff --git a/backend/server/app.js b/backend/server/app.js
index 0686bff..00a9822 100644
--- a/backend/server/app.js
+++ b/backend/server/app.js
@@ -1,20 +1,27 @@
-let express = require('express');
-let session = require('express-session')
-let path = require('path');
-let cookieParser = require('cookie-parser');
-let logger = require('morgan');
-
-let cypherRouter = require('./api/cypher/cypherController');
-let databaseRouter = require('./api/database/databaseController');
+const express = require('express');
+const session = require('express-session');
+const path = require('path');
+const cookieParser = require('cookie-parser');
+const logger = require('morgan');
+const supertest = require('supertest');
+const cypherRouter = require('./application/cypher/cypherController');
+const databaseRouter = require('./application/connector/connectorController');
 
 let app = express();
 
-app.use(session({
-    secret: 'bitnine123!',
-    resave: true,
-    saveUninitialized: true,
-    proxy: true
-}));
+app.use(express.static(path.join(__dirname, '../../frontend/build')));
+app.get('/', function (req, res) {
+    res.sendFile(path.join(__dirname, '../../frontend/build', 'index.html'));
+});
+
+app.use(
+    session({
+        secret: 'bitnine123!',
+        resave: true,
+        saveUninitialized: true,
+        proxy: true,
+    })
+);
 app.use(logger('dev'));
 app.use(express.json());
 app.use(express.urlencoded({ extended: false }));
@@ -23,4 +30,8 @@
 app.use('/api/v1/cypher', cypherRouter);
 app.use('/api/v1/db', databaseRouter);
 
+process.on('uncaughtException', function (exception) {
+    console.log(exception);
+});
+
 module.exports = app;
diff --git a/backend/server/application/connector/connectorController.js b/backend/server/application/connector/connectorController.js
new file mode 100644
index 0000000..81fefa4
--- /dev/null
+++ b/backend/server/application/connector/connectorController.js
@@ -0,0 +1,42 @@
+const express = require('express');
+const ConnectorService = require('./connectorService')
+const AgensDatabaseHelper = require('../db/agensDatabaseHelper');
+const router = express.Router();
+
+router.get('/', async (req, res, next) => {
+    let agensDatabaseHelper = new AgensDatabaseHelper(req.session.client);
+
+    let connectorService = new ConnectorService(req.session, agensDatabaseHelper);
+    let {status, data} = await connectorService.getConnectionStatus();
+
+    res.status(status).json(data).end();
+});
+
+router.post('/connect', async (req, res, next) => {
+    let agensDatabaseHelper = new AgensDatabaseHelper(req.body);
+
+    let connectorService = new ConnectorService(req.session, agensDatabaseHelper);
+    let {status, data} = await connectorService.connectDatabase();
+
+    res.status(status).json(data).end();
+});
+
+router.get('/disconnect', (req, res, next) => {
+    let agensDatabaseHelper = new AgensDatabaseHelper(req.session.client);
+
+    let connectorService = new ConnectorService(req.session, agensDatabaseHelper);
+    let {status, data} = connectorService.disconnectDatabase();
+
+    res.status(status).json(data).end();
+});
+
+router.get('/meta', async (req, res, next) => {
+    let agensDatabaseHelper = new AgensDatabaseHelper(req.session.client);
+
+    let connectorService = new ConnectorService(req.session, agensDatabaseHelper);
+    let metadata = await connectorService.getMetaData();
+
+    res.status(200).json(metadata).end();
+});
+
+module.exports = router;
diff --git a/backend/server/application/connector/connectorService.js b/backend/server/application/connector/connectorService.js
new file mode 100644
index 0000000..cac3ca6
--- /dev/null
+++ b/backend/server/application/connector/connectorService.js
@@ -0,0 +1,122 @@
+class ConnectorService {
+    constructor(session, agensDatabaseHelper) {
+        this._session = session;
+        this._agensDatabaseHelper = agensDatabaseHelper;
+    }
+
+    async getMetaData() {
+        let metadata = new Object();
+        metadata.nodes = await this.getNodes();
+        metadata.edges = await this.getEdges();
+        metadata.propertyKeys = await this.getPropertyKeys();
+        return metadata;
+    }
+
+    async getNodes(label) {
+        let agensDatabaseHelper = this._agensDatabaseHelper;
+        let query = [];
+        query.push("MATCH(v) RETURN DISTINCT '*' AS label, count(v) AS cnt");
+        query.push('UNION ALL');
+        query.push('MATCH(v) RETURN DISTINCT label(v) AS label, count(v) AS cnt');
+        query.push('ORDER BY label');
+
+        let queryResult = await agensDatabaseHelper.execute(query.join('\n'));
+        return queryResult.rows;
+    }
+
+    async getEdges(label) {
+        let agensDatabaseHelper = this._agensDatabaseHelper;
+        let query = [];
+        query.push("MATCH(v) - [e] - (v2) RETURN DISTINCT '*' AS label, count(e) AS cnt");
+        query.push('UNION ALL');
+        query.push('MATCH(v) - [e] - (v2) RETURN DISTINCT label(e) AS label, count(e) AS cnt');
+        query.push('ORDER BY label');
+
+        let queryResult = await agensDatabaseHelper.execute(query.join('\n'));
+        return queryResult.rows;
+    }
+
+    async getPropertyKeys() {
+        let agensDatabaseHelper = this._agensDatabaseHelper;
+        let query = [];
+        query.push('MATCH(v)');
+        query.push("RETURN DISTINCT jsonb_object_keys(v) AS key, 'v' AS key_type");
+        query.push('UNION ALL');
+        query.push('MATCH(v1) - [e] - (v2)');
+        query.push("RETURN DISTINCT jsonb_object_keys(e) AS key, 'e' AS key_type");
+
+        let queryResult = await agensDatabaseHelper.execute(query.join('\n'));
+        return queryResult.rows;
+    }
+
+    async connectDatabase() {
+        let agensDatabaseHelper = this._agensDatabaseHelper;
+        let status, data;
+
+        if (await agensDatabaseHelper.isHealth()) {
+            this._session.client = agensDatabaseHelper.toConnectionInfo();
+            data = agensDatabaseHelper.toConnectionInfo();
+            status = 200;
+        } else {
+            data = null;
+            status = 500;
+        }
+
+        return {
+            status: status,
+            data: data,
+        };
+    }
+
+    disconnectDatabase() {
+        let status = 200,
+            data = null;
+        try {
+            this._session.client = null;
+        } catch (err) {
+            console.log("Already Disconnected");
+        }
+        return {
+            status: status,
+            data: data,
+        };
+    }
+
+    async getConnectionStatus() {
+        let agensDatabaseHelper = this._agensDatabaseHelper;
+        let status, data;
+
+        if (await agensDatabaseHelper.isHealth()) {
+            data = agensDatabaseHelper.toConnectionInfo();
+            status = 200;
+        } else {
+            data = null;
+            status = 500;
+        }
+
+        return {
+            status: status,
+            data: data,
+        };
+    }
+
+    convertEdge({ label, id, start, end, props }) {
+        return {
+            label: label,
+            id: `${id.oid}.${id.id}`,
+            start: `${start.oid}.${start.id}`,
+            end: `${end.oid}.${end.id}`,
+            properties: props,
+        };
+    }
+
+    convertVertex({ label, id, props }) {
+        return {
+            label: label,
+            id: `${id.oid}.${id.id}`,
+            properties: props,
+        };
+    }
+}
+
+module.exports = ConnectorService;
diff --git a/backend/server/application/cypher/cypherController.js b/backend/server/application/cypher/cypherController.js
new file mode 100644
index 0000000..084cef0
--- /dev/null
+++ b/backend/server/application/cypher/cypherController.js
@@ -0,0 +1,20 @@
+const express = require('express');
+const ag = require('agensgraph');
+const CypherService = require('./cypherService')
+const AgensDatabaseHelper = require('../db/agensDatabaseHelper')
+
+let router = express.Router();
+
+router.post('/', async (req, res, next) => {
+
+    let agensDatabaseHelper = new AgensDatabaseHelper(req.session.client);
+
+    let cypherService = new CypherService(agensDatabaseHelper);
+    let {status, data} = await cypherService.executeCypher(req.body.cmd);
+
+    res.status(status).json(data).end();
+});
+
+
+
+module.exports = router;
diff --git a/backend/server/application/cypher/cypherService.js b/backend/server/application/cypher/cypherService.js
new file mode 100644
index 0000000..a5de70a
--- /dev/null
+++ b/backend/server/application/cypher/cypherService.js
@@ -0,0 +1,80 @@
+class CypherService {
+    constructor(agensDatabaseHelper) {
+        this._agensDatabaseHelper = agensDatabaseHelper;
+    }
+
+    async executeCypher(query) {
+        let agensDatabaseHelper = this._agensDatabaseHelper;
+        let result = {
+            status: 200,
+            data: null,
+        };
+
+        if (!query) {
+            result.status = 400;
+            result.data = { cmd: query };
+        } else {
+            if (await agensDatabaseHelper.isHealth()) {
+                result.status = 200;
+                result.data = await this.getExecuteResult(query);
+            } else {
+                result.data = agensDatabaseHelper.toConnectionInfo();
+                result.status = 500;
+            }
+        }
+
+        return result;
+    }
+
+    async getExecuteResult(query) {
+        let agensDatabaseHelper = this._agensDatabaseHelper;
+        try {
+            let queryResult = await agensDatabaseHelper.execute(query);
+            let result = {
+                rows: null,
+                columns: queryResult.fields.map((field) => field.name),
+                rowCount: queryResult.rowCount,
+                command: queryResult.command
+            }
+
+            result.rows = queryResult.rows.map((row) => {
+                let convetedObject = {};
+                for (let k in row) {
+                    if (row[k].hasOwnProperty('start')) {
+                        convetedObject[k] = this.convertEdge(row[k]);
+                    } else if (row[k].hasOwnProperty('id')) {
+                        convetedObject[k] = this.convertVertex(row[k]);
+                    } else {
+                        convetedObject[k] = row[k];
+                    }
+                }
+                return convetedObject;
+            });
+
+            return result;
+        } catch (err) {
+            console.log(err);
+            throw err;
+        }
+    }
+
+    convertEdge({ label, id, start, end, props }) {
+        return {
+            label: label,
+            id: `${id.oid}.${id.id}`,
+            start: `${start.oid}.${start.id}`,
+            end: `${end.oid}.${end.id}`,
+            properties: props,
+        };
+    }
+
+    convertVertex({ label, id, props }) {
+        return {
+            label: label,
+            id: `${id.oid}.${id.id}`,
+            properties: props,
+        };
+    }
+}
+
+module.exports = CypherService;
diff --git a/backend/server/application/db/agensDatabaseHelper.js b/backend/server/application/db/agensDatabaseHelper.js
new file mode 100644
index 0000000..a35ef7e
--- /dev/null
+++ b/backend/server/application/db/agensDatabaseHelper.js
@@ -0,0 +1,85 @@
+const { Pool } = require('agensgraph');
+
+class AgensDatabaseHelper {
+    constructor({ host, port, database, graph, user, password } = {}) {
+        this._host = host;
+        this._port = port;
+        this._database = database;
+        this._graph = graph;
+        this._user = user;
+        this._password = password;
+    }
+
+    async isHealth() {
+        let result = false;
+        if(this.toPoolConnectionInfo() == null) {
+            return result;
+        }
+
+        let client = await this.getConnection();
+        try {
+            await client.query('SELECT 1');
+            result = true;
+        } catch (err) {
+            console.error('Error Occurred!!!: ', err);
+        } finally {
+            client.release();
+        }
+
+        return result;
+    }
+
+    async execute(query) {
+        let client = await this.getConnection();
+        let result = null;
+        try {
+            await client.query(`set graph_path=${this._graph}`);
+            result = await client.query(query);
+        } catch (err) {
+            console.error('Error Occurred!!!: ', err);
+            next(err);
+        } finally {
+            client.release();
+        }
+        return result;
+    }
+
+    getConnection() {
+        if (!this._pool) {
+            this._pool = new Pool(this.toPoolConnectionInfo());
+        }
+        return this._pool.connect();
+    }
+
+    toPoolConnectionInfo() {
+        if(!this._host || !this._port || !this._database) {
+            return null;
+        }
+        return {
+            host: this._host,
+            port: this._port,
+            database: this._database,
+            user: this._user,
+            password: this._password,
+            max: 10,
+            idleTimeoutMillis: 30000,
+            connectionTimeoutMillis: 2000,
+        };
+    }
+
+    toConnectionInfo() {
+        if(!this._host || !this._port || !this._database) {
+            return null;
+        }
+        return {
+            host: this._host,
+            port: this._port,
+            database: this._database,
+            user: this._user,
+            password: this._password,
+            graph: this._graph,
+        };
+    }
+}
+
+module.exports = AgensDatabaseHelper;
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 9907409..526325b 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -2104,6 +2104,11 @@
       "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
     },
+    "@zeit/schemas": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz",
+      "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg=="
+    },
     "abab": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
@@ -2231,6 +2236,43 @@
       "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
       "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
     },
+    "ansi-align": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
+      "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
+      "requires": {
+        "string-width": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+        },
+        "string-width": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+          "requires": {
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^4.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
+      }
+    },
     "ansi-colors": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
@@ -2283,6 +2325,16 @@
       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
       "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
     },
+    "arch": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz",
+      "integrity": "sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ=="
+    },
+    "arg": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz",
+      "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w=="
+    },
     "argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -2477,6 +2529,14 @@
         "postcss-value-parser": "^4.1.0"
       }
     },
+    "avsdf-base": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/avsdf-base/-/avsdf-base-1.0.0.tgz",
+      "integrity": "sha512-APhZNUFJwIwrLsSfE95QjobEntdUhFQgfNtC/BrYmjUpwHh5Y2fbRv8lxAlMr1hdf/CuQYsqJxK3dRzcCL77qw==",
+      "requires": {
+        "layout-base": "^1.0.0"
+      }
+    },
     "aws-sign2": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -3093,6 +3153,54 @@
       "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.0.tgz",
       "integrity": "sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA=="
     },
+    "boxen": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
+      "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
+      "requires": {
+        "ansi-align": "^2.0.0",
+        "camelcase": "^4.0.0",
+        "chalk": "^2.0.1",
+        "cli-boxes": "^1.0.0",
+        "string-width": "^2.0.0",
+        "term-size": "^1.2.0",
+        "widest-line": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+        },
+        "camelcase": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+        },
+        "string-width": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+          "requires": {
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^4.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
+      }
+    },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -3555,6 +3663,11 @@
       "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
       "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
     },
+    "cli-boxes": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
+      "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM="
+    },
     "cli-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -3568,6 +3681,60 @@
       "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
       "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw=="
     },
+    "clipboardy": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.2.3.tgz",
+      "integrity": "sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==",
+      "requires": {
+        "arch": "^2.1.0",
+        "execa": "^0.8.0"
+      },
+      "dependencies": {
+        "cross-spawn": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "requires": {
+            "lru-cache": "^4.0.1",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
+        "execa": {
+          "version": "0.8.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz",
+          "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=",
+          "requires": {
+            "cross-spawn": "^5.0.1",
+            "get-stream": "^3.0.0",
+            "is-stream": "^1.1.0",
+            "npm-run-path": "^2.0.0",
+            "p-finally": "^1.0.0",
+            "signal-exit": "^3.0.0",
+            "strip-eof": "^1.0.0"
+          }
+        },
+        "get-stream": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+          "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+        },
+        "lru-cache": {
+          "version": "4.1.5",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+          "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+          "requires": {
+            "pseudomap": "^1.0.2",
+            "yallist": "^2.1.2"
+          }
+        },
+        "yallist": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+          "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
+        }
+      }
+    },
     "cliui": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -4257,6 +4424,23 @@
         "lodash.debounce": "^4.0.8"
       }
     },
+    "cytoscape-avsdf": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/cytoscape-avsdf/-/cytoscape-avsdf-1.0.0.tgz",
+      "integrity": "sha512-Wzd2wmJgr4dK5avHy4nKHp3D8TBZ8H/+5Hq5o24bRdVTvXlhSDzQhAMtzOuhRPYwHcWB+cBhEAXboAK8n7zPTQ==",
+      "requires": {
+        "avsdf-base": "^1.0.0"
+      }
+    },
+    "cytoscape-cise": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/cytoscape-cise/-/cytoscape-cise-1.0.0.tgz",
+      "integrity": "sha512-Y1NPaUo4fN992XJTEIDd4oPVkv8BsDSrFBHSB38caDu8PcmHUyl8/Q8K5wvqdTeti1mLR9IX4/o2RyuObh+P7Q==",
+      "requires": {
+        "avsdf-base": "^1.0.0",
+        "cose-base": "^1.0.0"
+      }
+    },
     "cytoscape-cose-bilkent": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz",
@@ -4265,6 +4449,24 @@
         "cose-base": "^1.0.0"
       }
     },
+    "cytoscape-cxtmenu": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/cytoscape-cxtmenu/-/cytoscape-cxtmenu-3.1.2.tgz",
+      "integrity": "sha512-ikPWyNRZ6IfIykXU9J6tXkwu2Gk3nYK5yNmNJI/wtLFCuELdcCqpEXobgGLDT7yEGO+jI1upxmb4Lex/DPZlgA=="
+    },
+    "cytoscape-d3-force": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/cytoscape-d3-force/-/cytoscape-d3-force-1.1.4.tgz",
+      "integrity": "sha512-8NjI/yEoB3YqVsdf7ud7Oh8Kyi+C9Lhh1fICmtemIo6EC1ZUtm8KcPNLkQySYO8nRS2mQKj5eVdCr7W0L8ONoQ==",
+      "requires": {
+        "d3-force": "^2.0.1"
+      }
+    },
+    "cytoscape-euler": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/cytoscape-euler/-/cytoscape-euler-1.2.2.tgz",
+      "integrity": "sha512-A24ZGrFpqCOutTIlGoXA5kmjFj68iy7HvqXuhcZUL1a7Z8bL59Bl2bB7hkSvFcCZBVCNcArxKr+YlB8bJo9Ftw=="
+    },
     "d": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
@@ -4274,6 +4476,31 @@
         "type": "^1.0.1"
       }
     },
+    "d3-dispatch": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz",
+      "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA=="
+    },
+    "d3-force": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-2.0.1.tgz",
+      "integrity": "sha512-zh73/N6+MElRojiUG7vmn+3vltaKon7iD5vB/7r9nUaBeftXMzRo5IWEG63DLBCto4/8vr9i3m9lwr1OTJNiCg==",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-quadtree": "1",
+        "d3-timer": "1"
+      }
+    },
+    "d3-quadtree": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz",
+      "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA=="
+    },
+    "d3-timer": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz",
+      "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw=="
+    },
     "damerau-levenshtein": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
@@ -4340,6 +4567,11 @@
         "regexp.prototype.flags": "^1.2.0"
       }
     },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+    },
     "deep-is": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -5741,6 +5973,21 @@
       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
     },
+    "fast-url-parser": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
+      "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=",
+      "requires": {
+        "punycode": "^1.3.2"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "1.4.1",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+        }
+      }
+    },
     "faye-websocket": {
       "version": "0.10.0",
       "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
@@ -10292,6 +10539,11 @@
       "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
       "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
     },
+    "pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
+    },
     "psl": {
       "version": "1.8.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -10434,6 +10686,24 @@
         }
       }
     },
+    "rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "requires": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "dependencies": {
+        "strip-json-comments": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+          "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+        }
+      }
+    },
     "react": {
       "version": "16.13.1",
       "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
@@ -11276,6 +11546,23 @@
         "unicode-match-property-value-ecmascript": "^1.2.0"
       }
     },
+    "registry-auth-token": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz",
+      "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==",
+      "requires": {
+        "rc": "^1.1.6",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "registry-url": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
+      "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
+      "requires": {
+        "rc": "^1.0.1"
+      }
+    },
     "regjsgen": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz",
@@ -11790,6 +12077,122 @@
       "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
       "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ=="
     },
+    "serve": {
+      "version": "11.3.2",
+      "resolved": "https://registry.npmjs.org/serve/-/serve-11.3.2.tgz",
+      "integrity": "sha512-yKWQfI3xbj/f7X1lTBg91fXBP0FqjJ4TEi+ilES5yzH0iKJpN5LjNb1YzIfQg9Rqn4ECUS2SOf2+Kmepogoa5w==",
+      "requires": {
+        "@zeit/schemas": "2.6.0",
+        "ajv": "6.5.3",
+        "arg": "2.0.0",
+        "boxen": "1.3.0",
+        "chalk": "2.4.1",
+        "clipboardy": "1.2.3",
+        "compression": "1.7.3",
+        "serve-handler": "6.1.3",
+        "update-check": "1.5.2"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.5.3",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz",
+          "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==",
+          "requires": {
+            "fast-deep-equal": "^2.0.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "chalk": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+          "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "compression": {
+          "version": "1.7.3",
+          "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz",
+          "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==",
+          "requires": {
+            "accepts": "~1.3.5",
+            "bytes": "3.0.0",
+            "compressible": "~2.0.14",
+            "debug": "2.6.9",
+            "on-headers": "~1.0.1",
+            "safe-buffer": "5.1.2",
+            "vary": "~1.1.2"
+          }
+        },
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "fast-deep-equal": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+          "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
+      }
+    },
+    "serve-handler": {
+      "version": "6.1.3",
+      "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz",
+      "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==",
+      "requires": {
+        "bytes": "3.0.0",
+        "content-disposition": "0.5.2",
+        "fast-url-parser": "1.1.3",
+        "mime-types": "2.1.18",
+        "minimatch": "3.0.4",
+        "path-is-inside": "1.0.2",
+        "path-to-regexp": "2.2.1",
+        "range-parser": "1.2.0"
+      },
+      "dependencies": {
+        "content-disposition": {
+          "version": "0.5.2",
+          "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
+          "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
+        },
+        "mime-db": {
+          "version": "1.33.0",
+          "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
+          "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
+        },
+        "mime-types": {
+          "version": "2.1.18",
+          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
+          "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
+          "requires": {
+            "mime-db": "~1.33.0"
+          }
+        },
+        "path-to-regexp": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
+          "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ=="
+        },
+        "range-parser": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+          "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
+        }
+      }
+    },
     "serve-index": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
@@ -12690,6 +13093,59 @@
       "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
       "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="
     },
+    "term-size": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
+      "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
+      "requires": {
+        "execa": "^0.7.0"
+      },
+      "dependencies": {
+        "cross-spawn": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "requires": {
+            "lru-cache": "^4.0.1",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
+        "execa": {
+          "version": "0.7.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+          "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+          "requires": {
+            "cross-spawn": "^5.0.1",
+            "get-stream": "^3.0.0",
+            "is-stream": "^1.1.0",
+            "npm-run-path": "^2.0.0",
+            "p-finally": "^1.0.0",
+            "signal-exit": "^3.0.0",
+            "strip-eof": "^1.0.0"
+          }
+        },
+        "get-stream": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+          "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+        },
+        "lru-cache": {
+          "version": "4.1.5",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+          "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+          "requires": {
+            "pseudomap": "^1.0.2",
+            "yallist": "^2.1.2"
+          }
+        },
+        "yallist": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+          "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
+        }
+      }
+    },
     "terser": {
       "version": "4.8.0",
       "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
@@ -13142,6 +13598,15 @@
       "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
       "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
     },
+    "update-check": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.2.tgz",
+      "integrity": "sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==",
+      "requires": {
+        "registry-auth-token": "3.3.2",
+        "registry-url": "3.1.0"
+      }
+    },
     "uri-js": {
       "version": "4.2.2",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@@ -14006,6 +14471,43 @@
       "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
       "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
     },
+    "widest-line": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
+      "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
+      "requires": {
+        "string-width": "^2.1.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+        },
+        "string-width": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+          "requires": {
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^4.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
+      }
+    },
     "word-wrap": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 966b51f..d76b47d 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -11,7 +11,12 @@
     "axios": "^0.19.2",
     "bootstrap": "^4.5.0",
     "cytoscape": "^3.2.19",
+    "cytoscape-avsdf": "^1.0.0",
+    "cytoscape-cise": "^1.0.0",
     "cytoscape-cose-bilkent": "^4.1.0",
+    "cytoscape-cxtmenu": "^3.1.2",
+    "cytoscape-d3-force": "^1.1.4",
+    "cytoscape-euler": "^1.2.2",
     "react": "^16.13.1",
     "react-bootstrap": "^1.2.2",
     "react-cytoscapejs": "^1.2.1",
@@ -20,7 +25,8 @@
     "react-scripts": "3.4.1",
     "react-uuid": "^1.0.2",
     "redux": "^4.0.5",
-    "redux-thunk": "^2.3.0"
+    "redux-thunk": "^2.3.0",
+    "serve": "^11.3.2"
   },
   "scripts": {
     "start": "react-scripts start",
@@ -45,7 +51,6 @@
     ]
   },
   "devDependencies": {
-    "webpack": "^4.42.0",
     "webpack-dev-server": "^3.10.3"
   }
 }
diff --git a/frontend/public/css/style.css b/frontend/public/css/style.css
index 81cf4bb..a7e9e47 100644
--- a/frontend/public/css/style.css
+++ b/frontend/public/css/style.css
@@ -86,9 +86,8 @@
     width: 70px;
     background-color: var(--navbar-color);
 }
-
 #sidebar {
-    width: 250px;
+    width: 320px;
     position: fixed;
     top: 0;
     left: 70px;
@@ -97,13 +96,28 @@
     background-color: var(--sidebar-color);
     color: #fff;
     transition: all 0.3s;
-    margin-left: -250px;
+    margin-left: -320px;
 }
-
 #sidebar.active {
     margin-left: 0px;
 }
 
+/*
+#sidebar {
+    width: 0;
+    position: fixed;
+    top: 0;
+    left: 70px;
+    height: 100vh;
+    background-color: var(--sidebar-color);
+    color: #fff;
+    transition: all 0.3s;
+}
+#sidebar.active {
+    width: 320px;
+}
+*/
+
 a[data-toggle="collapse"] {
     position: relative;
 }
@@ -128,19 +142,25 @@
     background-color: var(--bg-color);
     color: var(--text-color);
 }
+/*
+#sidebar.active~#content{
+    width: calc(100% - 390px);
+}
+*/
 
 #content.active {
-    width: calc(100% - 320px);
+    width: calc(100% - 390px);
     
 }
 
+
 /* ---------------------------------------------------
     MEDIAQUERIES
 ----------------------------------------------------- */
 
 @media (max-width: 768px) {
     #sidebar {
-        margin-left: -250px;
+        margin-left: -320px;
     }
     #sidebar.active {
         margin-left: 0;
@@ -149,7 +169,7 @@
         width: 100%;
     }
     #content.active {
-        width: calc(100% - 250px);
+        width: calc(100% - 320px);
     }
     #sidebarCollapse span {
         display: none;
@@ -160,6 +180,18 @@
     color: gray !important;
 }
 
+.card.fullscreen {
+    position: fixed;
+    left: 0;
+    top: 0;
+    width: 100vw;
+    height: 100vh;
+    z-index: 1040;
+}
+
+.card.fullscreen .chart-area {
+    height: calc(100% - 94px - 35px)
+}
 .card-header {
     border-bottom: 1px solid rgba(0,0,0,.125);    
 }
@@ -212,11 +244,116 @@
     margin-bottom: 0px;
 }
 
-.chart-area {
-    height:100%; 
+.chart-frame-area {
     width:100%;
+    height:100%;
+
 }
+.chart-area {
+    height: 317px;
+    width: 100%;
+    display: 'block';
+    overflow:hidden;
+}
+
+.chart-footer-area {
+    vertical-align: middle;
+    line-height: 37px;       
+    min-height: 37px;
+    width: 100%;
+    background-color: rgba(0,0,0,.03);
+    border-top: 1px solid rgba(0,0,0,.125);
+}
+
 
 .frame-head-button:hover {
     color: #212121 !important;
+}
+
+.graph-tabpanel {
+    padding-left: 0px !important;
+    padding-right: 0px !important;
+}
+
+.nodeLegend, .edgeLegend {
+    height: 47px;
+    width: 100%;
+    padding-left: 15px;
+    padding-right: 15px;
+    background-color: rgba(0,0,0,.03);
+    border-bottom: 1px solid rgba(0,0,0,.125);
+}
+
+.nodeLabel, .edgeLabel {
+    cursor: pointer;
+}
+
+.colorSelector {
+    width: 15px; 
+    height: 15px; 
+    padding: 6px 0px; 
+    border-radius: 15px; 
+    font-size: 8px; 
+    text-align: center; 
+    margin-left: 5px;
+    opacity: 0.2; 
+}
+
+.captionSelector {
+    padding: .1rem .2rem;
+    font-size: .575rem;
+    line-height: 1.5;
+    border-radius: .2rem;
+    margin-left: 5px;
+    border-color: darkgrey;
+    opacity: 0.5; 
+}
+
+.sizeSelector.node {
+    background-color: darkgrey;
+    padding: 6px 0px; 
+    border-radius: 15px; 
+    font-size: 8px; 
+    text-align: center; 
+    margin-left: 5px;
+    opacity: 0.2; 
+}
+
+.sizeSelector.edge {
+    background-color: darkgrey;
+    padding: 6px 0px; 
+    font-size: 8px; 
+    text-align: center; 
+    margin-left: 5px;
+    opacity: 0.2; 
+}
+
+.sizeSelector:hover {
+    opacity: 1; 
+}
+
+.sizeSelector.selectedSize {
+    opacity: 1; 
+}
+
+.colorSelector:hover {
+    opacity: 1; 
+}
+
+.colorSelector.selectedColor {
+    opacity: 1; 
+}
+
+.captionSelector.selectedCaption {
+    opacity: 1; 
+}
+
+
+
+
+/* ---------------------------------------------------
+    Cytoscapejs-cxtmenu
+----------------------------------------------------- */
+.cxtmenu-content {
+    font-size: 10px;
 }
\ No newline at end of file
diff --git a/frontend/public/index.html b/frontend/public/index.html
index 2c9722f..288146d 100644
--- a/frontend/public/index.html
+++ b/frontend/public/index.html
@@ -39,7 +39,9 @@
         href="https://cdnjs.cloudflare.com/ajax/libs/malihu-custom-scrollbar-plugin/3.1.5/jquery.mCustomScrollbar.min.css">
 
     <!-- Fontawesome CSS -->
-    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+    <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> -->
+    <script src="https://kit.fontawesome.com/8919a0422e.js" crossorigin="anonymous"></script>
+
 
     <!-- Google Poppins Webfont -->
     <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Poppins" />
diff --git a/frontend/src/app/reducers.js b/frontend/src/app/reducers.js
index 9df8112..79b7f0f 100644
--- a/frontend/src/app/reducers.js
+++ b/frontend/src/app/reducers.js
@@ -1,5 +1,6 @@
 import { combineReducers } from 'redux'
 import DatabaseReducer from '../features/database/DatabaseSlice'
+import MetadataReducer from '../features/database/MetadataSlice'
 import FrameReducer from '../features/frame/FrameSlice'
 import MenuReducer from '../features/menu/MenuSlice'
 import SettingReducer from '../features/setting/SettingSlice'
@@ -11,6 +12,7 @@
     navigator : MenuReducer,
     setting : SettingReducer,
     database : DatabaseReducer,
+    metadata : MetadataReducer,
     frames : FrameReducer,
     cypher: CypherReducer,
     alerts: AlertReducer
diff --git a/frontend/src/components/alert/presentations/Alert.jsx b/frontend/src/components/alert/presentations/Alert.jsx
index a52cb72..b4f21e8 100644
--- a/frontend/src/components/alert/presentations/Alert.jsx
+++ b/frontend/src/components/alert/presentations/Alert.jsx
@@ -1,10 +1,15 @@
-import React, {useState} from 'react';
+import React, {useState, useEffect} from 'react';
 import {Alert} from 'react-bootstrap'
 
 const SingleAlert = ({key, alertKey, alertType}) => {
 
     const [show, setShow] = useState(true)
 
+    useEffect(() => {
+        const timer = setTimeout(() => {setShow(false)} , 5000)
+        return () => clearTimeout(timer);
+    }, [])
+
     if (alertType === 'NoticeServerDisconnected') {
         return (    
             <Alert show={show} variant="warning" onClose={() => setShow(false)} dismissible>
diff --git a/frontend/src/components/contents/containers/Contents.js b/frontend/src/components/contents/containers/Contents.js
index c4b2358..8d64aab 100644
--- a/frontend/src/components/contents/containers/Contents.js
+++ b/frontend/src/components/contents/containers/Contents.js
@@ -1,6 +1,6 @@
 import {connect} from 'react-redux'
+import {getConnectionStatus} from '../../../features/database/DatabaseSlice'
 import {addFrame} from '../../../features/frame/FrameSlice'
-import {addAlert} from '../../../features/alert/AlertSlice'
 import Contents from '../presentations/Contents'
 /*
 import React from 'react'
@@ -12,10 +12,8 @@
 
 const mapStateToProps = (state)  => {
     return {
-        activeMenuName: state.navigator.activeMenu,
-        frameList: state.frames,
-        alertList: state.alerts,
-        database: state.database
+        database: state.database,
+        isActive: state.navigator.isActive
     }
 }
 
@@ -52,7 +50,7 @@
 }
 */
 
-const mapDispatchToProps = { addFrame, addAlert }
+const mapDispatchToProps = { getConnectionStatus, addFrame }
 
 export default connect(mapStateToProps, mapDispatchToProps)(Contents);
 
diff --git a/frontend/src/components/contents/containers/Editor.js b/frontend/src/components/contents/containers/Editor.js
new file mode 100644
index 0000000..5ead064
--- /dev/null
+++ b/frontend/src/components/contents/containers/Editor.js
@@ -0,0 +1,17 @@
+import {connect} from 'react-redux'
+import {addFrame} from '../../../features/frame/FrameSlice'
+import {addAlert} from '../../../features/alert/AlertSlice'
+import {getConnectionStatus} from '../../../features/database/DatabaseSlice'
+import {executeCypherQuery} from '../../../features/cypher/CypherSlice'
+import Editor from '../presentations/Editor'
+const mapStateToProps = (state)  => {
+    return {
+        alertList: state.alerts,
+        database: state.database
+    }
+}
+
+
+const mapDispatchToProps = { addFrame, addAlert, getConnectionStatus, executeCypherQuery }
+
+export default connect(mapStateToProps, mapDispatchToProps)(Editor);
diff --git a/frontend/src/components/contents/containers/Frames.js b/frontend/src/components/contents/containers/Frames.js
new file mode 100644
index 0000000..9a78882
--- /dev/null
+++ b/frontend/src/components/contents/containers/Frames.js
@@ -0,0 +1,13 @@
+import {connect} from 'react-redux'
+import Frames from '../presentations/Frames'
+const mapStateToProps = (state)  => {
+    return {
+        frameList: state.frames,
+        queryResult : state.cypher.queryResult,
+        database: state.database
+    }
+}
+
+const mapDispatchToProps = { }
+
+export default connect(mapStateToProps, mapDispatchToProps)(Frames);
diff --git a/frontend/src/components/contents/presentations/Contents.jsx b/frontend/src/components/contents/presentations/Contents.jsx
index 6a0065b..430c57d 100644
--- a/frontend/src/components/contents/presentations/Contents.jsx
+++ b/frontend/src/components/contents/presentations/Contents.jsx
@@ -1,12 +1,22 @@
 import React from 'react';
-import Editor from '../presentations/Editor'
-import Frames from '../presentations/Frames'
+import {useDispatch} from 'react-redux'
+import EditorContainer from '../containers/Editor'
+import FramesContainer from '../containers/Frames'
 
-const Contents = ({ activeMenuName, frameList, alertList, addFrame, addAlert, database }) => {
+const Contents = ({ database, isActive, getConnectionStatus, addFrame }) => {
+    const dispatch = useDispatch();
+
+    if (database.status === 'init') {
+        dispatch(() => getConnectionStatus())
+    }
+    else if (database.status === 'disconnected') {
+        dispatch(() => addFrame(':server connect'))
+    }
+
     return (
-        <div id="content" className={activeMenuName !== "" ? " active " : ""}>
-                <Editor onClick={addFrame} addAlert={addAlert} alertList={alertList} serverInfo={database} />
-                <Frames frameList={frameList} serverInfo={database} />
+        <div id="content" className={isActive ? "active" : ""}>
+                <EditorContainer />
+                <FramesContainer />
         </div>
     );
 }
diff --git a/frontend/src/components/contents/presentations/Editor.jsx b/frontend/src/components/contents/presentations/Editor.jsx
index 58a02c6..9e1fdba 100644
--- a/frontend/src/components/contents/presentations/Editor.jsx
+++ b/frontend/src/components/contents/presentations/Editor.jsx
@@ -1,32 +1,34 @@
 import React, {useRef}  from 'react';
 import {useDispatch} from 'react-redux'
 import AlertContainers from '../../alert/containers/AlertContainers'
+import uuid from 'react-uuid'
 
 
-const Editor = ({ onClick, addAlert, alertList, serverInfo }) => {
+const Editor = ({ addFrame, addAlert, alertList, database, executeCypherQuery }) => {
+
     const dispatch = useDispatch();
     let reqString = useRef()
+
     const clearReqString = () => (reqString.current.value = '' );
     
     const onEnter = (e) => {
         if(e.keyCode === 13){
-            addFrame()
-            clearReqString()
+            onClick()
          }
     }
     
-    const addFrame = () => {
-        if (serverInfo.status === 'disconnected' && reqString.current.value.startsWith('match')) {
+    const onClick = () => {
+        const refKey = uuid()
+        if (database.status === 'disconnected' && reqString.current.value.match('(match|create).*')) {
             dispatch(() => addAlert('ErrorNoDatabaseConnected'))
-            return;
-        } if (serverInfo.status === 'disconnected' && reqString.current.value === ':server status') {
+        } else if (database.status === 'disconnected' && reqString.current.value === ':server status') {
             dispatch(() => addAlert('ErrorNoDatabaseConnected'))
-            return;
         } else {
-            dispatch(() => onClick(reqString.current.value))            
-            return;
+            dispatch(() => [addFrame(reqString.current.value, refKey), executeCypherQuery([refKey, reqString.current.value])])            
         }
+        clearReqString()
     }; 
+
     const alerts = alertList.map((alert) => {
         return <AlertContainers key={alert.alerProps.key} alertKey={alert.alerProps.key} alertType={alert.alertType}/>;
     });
@@ -43,7 +45,7 @@
                                 aria-hidden="true"></span></button>
                         <button className="frame-head-button btn btn-link" type="button"><span className="fa fa-eraser fa-lg"
                                 aria-hidden="true"></span></button>
-                        <button className="frame-head-button btn btn-link" type="button" onClick={() => [addFrame(), clearReqString()]}><span className="fa fa-play-circle-o fa-lg"
+                        <button className="frame-head-button btn btn-link" type="button" onClick={() => onClick()}><span className="fa fa-play-circle-o fa-lg"
                                 aria-hidden="true"></span></button>
                     </div>
                 </div>
diff --git a/frontend/src/components/contents/presentations/Frames.jsx b/frontend/src/components/contents/presentations/Frames.jsx
index 98cdc32..6a9ce40 100644
--- a/frontend/src/components/contents/presentations/Frames.jsx
+++ b/frontend/src/components/contents/presentations/Frames.jsx
@@ -2,10 +2,11 @@
 import ServerStatus from '../../../components/frame/containers/ServerStatusContainer'
 import ServerConnect from '../../../components/frame/containers/ServerConnectContainer'
 import ServerDisconnect from '../../../components/frame/containers/ServerDisconnectContainer'
-import CypherResult from '../../../components/frame/containers/CypherResultContainers'
+import CypherMatchResult from '../../../components/frame/containers/CypherMatchResultContainers'
+import CypherDmlResult from '../../../components/frame/containers/CypherDmlResultContainers'
 
 
-const Frames = ({ frameList }) => {
+const Frames = ({ frameList, queryResult }) => {
     const frames = frameList.map((frame) => {
         if (frame.frameName === 'ServerStatus') {
             return <ServerStatus key={frame.frameProps.key} refKey={frame.frameProps.key} reqString={frame.frameProps.reqString}/>;
@@ -14,7 +15,12 @@
         } else if (frame.frameName === 'ServerDisconnect') {
             return <ServerDisconnect key={frame.frameProps.key} refKey={frame.frameProps.key} reqString={frame.frameProps.reqString}/>;
         } else if (frame.frameName === 'CypherResultFrame') {
-            return <CypherResult key={frame.frameProps.key} refKey={frame.frameProps.key} reqString={frame.frameProps.reqString}/>;
+            if (queryResult.hasOwnProperty(frame.frameProps.key) && queryResult[frame.frameProps.key]['command'].toUpperCase() === 'GRAPH') {
+                return <CypherDmlResult key={frame.frameProps.key} refKey={frame.frameProps.key} reqString={frame.frameProps.reqString}/>;
+            } else {
+                return <CypherMatchResult key={frame.frameProps.key} refKey={frame.frameProps.key} reqString={frame.frameProps.reqString}/>;
+            }
+            
         }
         return '';
     });
diff --git a/frontend/src/components/cypherresult/containers/CypherResultCytoscapeContainer.js b/frontend/src/components/cypherresult/containers/CypherResultCytoscapeContainer.js
index 003fab6..ce2f416 100644
--- a/frontend/src/components/cypherresult/containers/CypherResultCytoscapeContainer.js
+++ b/frontend/src/components/cypherresult/containers/CypherResultCytoscapeContainer.js
@@ -1,53 +1,24 @@
 import { connect } from 'react-redux'
 import CypherResultCytoscape from '../presentations/CypherResultCytoscape'
+import {setLabels} from '../../../features/cypher/CypherSlice'
+import { generateCytoscapeElement, reGenerateCytoscapeElements } from '../../../features/cypher/CypherUtil'
 
 const mapStateToProps = (state, ownProps) => {
     const { refKey } = ownProps
 
-    const getRandomColor = () => {
-        var letters = '0123456789ABCDEF';
-        var color = '#';
-        for (var i = 0; i < 6; i++) {
-            color += letters[Math.floor(Math.random() * 16)];
+    const generateElements = () => {
+        if (Object.keys(state.cypher.labels.nodeLabels).length > 0) {
+            return reGenerateCytoscapeElements(state.cypher.queryResult[refKey], state.cypher.labels)
+        } else {
+            return generateCytoscapeElement(state.cypher.queryResult[refKey])
         }
-        return color;
+        
     }
-
-    const generateCytoscapeElement = (data) => {
-        let nodes = []
-        let edges = []
-        let nodeLegend = {}
-        let edgeLegend = {}
-
-        if (data) {
-            data['response']['data']['rows'].forEach((row, index) => {
-                for (const [alias, val] of Object.entries(row)) {
-                    let labelName = val['label']
-                    if (val['start'] && val['end']) {
-                        if (!edgeLegend.hasOwnProperty(labelName)) { edgeLegend[labelName] = getRandomColor() }
-                        edges.push(
-                            { group: 'edges', data: { id: val.id, source: val.start, target: val.end, label: val.label, backgroundColor: edgeLegend[labelName] }, alias: alias, backgroundColor: nodeLegend[labelName], classes: ['node'] }
-                        )
-                    } else {
-                        if (!nodeLegend.hasOwnProperty(labelName)) { nodeLegend[labelName] = getRandomColor() }
-                        nodes.push(
-                            { group: 'nodes', data: { id: val.id, label: val.label, backgroundColor: nodeLegend[labelName] }, alias: alias, backgroundColor: nodeLegend[labelName], classes: ['node'] }
-                        )
-                    }
-                }
-            });
-
-        }
-        return { legend : {nodeLegend: nodeLegend, edgeLegend: edgeLegend}, elements : { nodes: nodes, edges: edges }}
-
-    }
-
-
     return {
-        data: generateCytoscapeElement(state.cypher.queryResult[refKey])
+        data: generateElements()
     }
 }
 
-const mapDispatchToProps = {}
+const mapDispatchToProps = { setLabels }
 
 export default connect(mapStateToProps, mapDispatchToProps)(CypherResultCytoscape);
diff --git a/frontend/src/components/cypherresult/containers/CypherResultMetaContainer.js b/frontend/src/components/cypherresult/containers/CypherResultMetaContainer.js
index 79c8160..9f35142 100644
--- a/frontend/src/components/cypherresult/containers/CypherResultMetaContainer.js
+++ b/frontend/src/components/cypherresult/containers/CypherResultMetaContainer.js
@@ -9,8 +9,12 @@
     let data = {}
     if (state.cypher.queryResult[refKey]) {
         database = state.database
-        query = state.cypher.queryResult[refKey].response.query
-        data = state.cypher.queryResult[refKey].response.data
+        query = state.cypher.queryResult[refKey].query
+        data = {columns : state.cypher.queryResult[refKey].columns
+            , command : state.cypher.queryResult[refKey].command
+            , rowCount : state.cypher.queryResult[refKey].rowCount
+            , rows : state.cypher.queryResult[refKey].rows
+        }
     }
 
     return {
diff --git a/frontend/src/components/cypherresult/containers/CypherResultTableContainer.js b/frontend/src/components/cypherresult/containers/CypherResultTableContainer.js
index c8b16da..4eefbae 100644
--- a/frontend/src/components/cypherresult/containers/CypherResultTableContainer.js
+++ b/frontend/src/components/cypherresult/containers/CypherResultTableContainer.js
@@ -4,13 +4,18 @@
 const mapStateToProps = (state, ownProps) => {
     const { refKey } = ownProps
     const generateTableData = (data) => {
+        console.log(">>>>>>>>>>>>> ", data)
         let columns = []
         let rows = []
+        let command = null
+        let rowCount = null
         if (data) {
-            columns = data['response']['data']['columns']
-            rows = data['response']['data']['rows']
+            columns = data['columns']
+            rows = data['rows']
+            command = data['command']
+            rowCount = data['rowCount']
         }
-        return { columns: columns, rows: rows }
+        return { command : command, rowCount : rowCount, columns: columns, rows: rows }
     }
     return {
         data : generateTableData(state.cypher.queryResult[refKey])
diff --git a/frontend/src/components/cypherresult/containers/CypherResultTextContainer.js b/frontend/src/components/cypherresult/containers/CypherResultTextContainer.js
index 12fe6de..f29015c 100644
--- a/frontend/src/components/cypherresult/containers/CypherResultTextContainer.js
+++ b/frontend/src/components/cypherresult/containers/CypherResultTextContainer.js
@@ -7,8 +7,8 @@
         let columns = []
         let rows = []
         if (data) {
-            columns = data['response']['data']['columns']
-            rows = data['response']['data']['rows']
+            columns = data['columns']
+            rows = data['rows']
         }
         return { columns: columns, rows: rows }
     }
diff --git a/frontend/src/components/cypherresult/presentations/CypherResultCytoscape.jsx b/frontend/src/components/cypherresult/presentations/CypherResultCytoscape.jsx
index f7f3086..98acc09 100644
--- a/frontend/src/components/cypherresult/presentations/CypherResultCytoscape.jsx
+++ b/frontend/src/components/cypherresult/presentations/CypherResultCytoscape.jsx
@@ -1,95 +1,148 @@
-import React, {useRef, useLayoutEffect, useEffect, useState} from 'react';
-import Cytoscape from 'cytoscape';
-import COSEBilkent from 'cytoscape-cose-bilkent';
+import React, { forwardRef, useEffect, useRef, useState, useImperativeHandle } from 'react';
+import { useDispatch } from 'react-redux'
+import { labelColors, nodeLabelSizes, edgeLabelSizes } from '../../../features/cypher/CypherUtil'
+import CypherResultCytoscapeChart from './CypherResultCytoscapeChart'
 import CypherResultCytoscapeLegend from './CypherResultCytoscapeLegend'
-
-Cytoscape.use(COSEBilkent);
-
-const CypherResultCytoscape = ({data}) => {
-
-    const targetRef = useRef();
-    const [dimensions, setDimensions] = useState({width: 0 , height: 0});
-
-    useLayoutEffect(() => {
-        if (targetRef.current) {
-          setDimensions({
-            width: targetRef.current.offsetWidth,
-            height: targetRef.current.offsetHeight
-          });
-        }
-    }, []);  
+import CypherResultCytoscapeFooter from './CypherResultCytoscapeFooter'
 
 
-    const containerRef = useRef();
+const CypherResultCytoscape = forwardRef((props, ref) => {
+  const [footerData, setFooterData] = useState({})
+  const [legendData, setLegendData] = useState({ edgeLegend: {}, nodeLegend: {} })
+  const [elements, setElements] = useState({ edges: [], nodes: [] })
+  const [isReloading, setIsReloading] = useState(false)
+  const dispatch = useDispatch()
+  const chartRef = useRef()
 
-    useEffect(() => {
-      const stylesheet = [
-        {
-          selector: 'node',
-          style: {
-            width: 70,
-            height: 70,
-            label: 'data(label)',
-            'background-color': function( ele ) { return ele == null ? '#FFF' : ele.data('backgroundColor'); },
-            "text-valign" : "center",
-            "text-halign" : "center"
-          }
-        },
-        {
-          selector: 'edge',
-          style: {
-            width: 6,
-            'line-color': function( ele ) { return ele == null ? '#FFF' : ele.data('backgroundColor'); }
-          }
-        }
-      ]
+  useEffect(() => {
 
-      const layout = { name : 'cose-bilkent' }
-      
-      const config = {
-        // Common Options
-        container: containerRef.current,
-        style: stylesheet,
-        elements: data['elements'],
-        layout: layout,
-        // Viewport Options
-        zoom: 1,
-        pan: { x: 0, y: 0 },
-        // Interaction Options
-        minZoom: 1e-50,
-        maxZoom: 1e50,
-        zoomingEnabled: true,
-        userZoomingEnabled: true,
-        panningEnabled: true,
-        userPanningEnabled: true,
-        boxSelectionEnabled: true,
-        selectionType: 'single',
-        touchTapThreshold: 8,
-        desktopTapThreshold: 4,
-        autolock: false,
-        autoungrabify: false,
-        autounselectify: false,
-        // Rendering Options
-        headless: false,
-        styleEnabled: true,
-        hideEdgesOnViewport: false,
-        textureOnViewport: false,
-        motionBlur: false,
-        motionBlurOpacity: 0.2,
-        wheelSensitivity: 1,
-        pixelRatio: 'auto'
-      };
-  
-      Cytoscape(config);
-    }, [data]);
+    if (props.data['legend'] !== undefined && Object.keys(props.data['legend']['nodeLegend']).length > 0) {
+
+      setIsReloading(false)
+
+      setLegendData(props.data['legend'])
+
+      setElements(props.data.elements)
+    }
+  })
+
+  const getFooterData = (props) => {
+    if (props.type === 'labels') {
+
+      props.data['captions'] = ['gid', 'label'].concat(Array.from(chartRef.current.getCaptions(props.data.type, props.data.label)))
+
+      if (props.data.type === 'node') {
+        props.data['selectedCaption'] = legendData.nodeLegend[props.data.label].caption
+      } else {
+        props.data['selectedCaption'] = legendData.edgeLegend[props.data.label].caption
+      }
+    }
+
+    setFooterData(props)
+  }
+
+  const addLegendData = (addedLegendData) => {
+    setIsReloading(false)
+    setLegendData(addedLegendData)
+  }
+
+  const colorChange = (elementType, label, color) => {
+    let footerObj = footerData.data
+    footerObj.backgroundColor = color.color
+    footerObj.fontColor = color.fontColor
+    setIsReloading(false)
+    setFooterData(Object.assign({}, footerData, { data: footerObj }))
+
+    if (elementType === 'node') {
+      let nodeLegendObj = legendData.nodeLegend
 
 
+      if (nodeLegendObj.hasOwnProperty(label)) {
+        nodeLegendObj[label]['color'] = color.color
+        nodeLegendObj[label]['borderColor'] = color.borderColor
+        nodeLegendObj[label]['fontColor'] = color.fontColor
+      }
+      setLegendData(Object.assign({}, legendData, { nodeLegend: nodeLegendObj }))
+      chartRef.current.colorChange(elementType, label, color);
 
-    return <div className="chart-area" ref={targetRef}>
-            <CypherResultCytoscapeLegend legendData={data['legend']}/>
-            <div ref={containerRef} style={ { width: dimensions.width , height: dimensions.height, position:'absolute', 'zIndex':1 } } />
-          </div>
-}
+    } else if (elementType === 'edge') {
+      let edgeLegendObj = legendData.edgeLegend
+      if (edgeLegendObj.hasOwnProperty(label)) {
+        edgeLegendObj[label]['color'] = color.color
+        edgeLegendObj[label]['borderColor'] = color.borderColor
+        edgeLegendObj[label]['fontColor'] = color.fontColor
+      }
+      setLegendData(Object.assign({}, legendData, { edgeLegend: edgeLegendObj }))
+      chartRef.current.colorChange(elementType, label, Object.assign(color, { fontColor: '#2A2C34' }));
+    }
+
+    dispatch(() => props.setLabels(elementType, label, { borderColor: color.borderColor, color: color.color, fontColor: color.fontColor }))
+  }
+
+  const sizeChange = (elementType, label, size) => {
+    let footerObj = footerData.data
+    footerObj.size = size
+    setFooterData(Object.assign({}, footerData, { data: footerObj }))
+    setIsReloading(false)
+    chartRef.current.sizeChange(elementType, label, size);
+
+    if (elementType === 'node') {
+      let nodeLegendObj = legendData.nodeLegend
+      if (nodeLegendObj.hasOwnProperty(label)) {
+        nodeLegendObj[label].size = size
+      }
+      setLegendData(Object.assign({}, legendData, { nodeLegend: nodeLegendObj }))
+    } else if (elementType === 'edge') {
+      let edgeLegendObj = legendData.edgeLegend
+      if (edgeLegendObj.hasOwnProperty(label)) {
+        edgeLegendObj[label].size = size
+      }
+      setLegendData(Object.assign({}, legendData, { edgeLegend: edgeLegendObj }))
+    }
+    dispatch(() => props.setLabels(elementType, label, { size: size }))
+  }
+
+  const captionChange = (elementType, label, caption) => {
+    chartRef.current.captionChange(elementType, label, caption);
+    let footerObj = footerData.data
+    footerObj.captions = ['gid', 'label'].concat(Array.from(chartRef.current.getCaptions(elementType, label)))
+    footerObj.selectedCaption = caption
+    setFooterData(Object.assign({}, footerData, { data: footerObj }))
+
+    if (elementType === 'node') {
+      let nodeLegendObj = legendData.nodeLegend
+      if (nodeLegendObj.hasOwnProperty(label)) {
+        nodeLegendObj[label].caption = caption
+      }
+      setLegendData(Object.assign({}, legendData, { nodeLegend: nodeLegendObj }))
+    } else if (elementType === 'edge') {
+      let edgeLegendObj = legendData.edgeLegend
+      if (edgeLegendObj.hasOwnProperty(label)) {
+        edgeLegendObj[label].caption = caption
+      }
+      setLegendData(Object.assign({}, legendData, { edgeLegend: edgeLegendObj }))
+    }
+    dispatch(() => props.setLabels(elementType, label, { caption: caption }))
+  }
+
+
+  useImperativeHandle(ref, () => ({
+
+    getCy() {
+      return chartRef.current.getCy();
+    },
+
+    resetChart() {
+      return chartRef.current.resetChart();
+    }
+  }));
+
+  return <div className="chart-frame-area">
+    <CypherResultCytoscapeLegend onLabelClick={getFooterData} isReloading={isReloading} legendData={legendData} />
+    <CypherResultCytoscapeChart onElementsMouseover={getFooterData} ref={chartRef} legendData={legendData} elements={elements} addLegendData={addLegendData} />
+    <CypherResultCytoscapeFooter colorChange={colorChange} sizeChange={sizeChange} captionChange={captionChange} footerData={footerData} nodeLabelSizes={nodeLabelSizes} edgeLabelSizes={edgeLabelSizes} labelColors={labelColors} />
+  </div>
+})
 
 
 export default CypherResultCytoscape
\ No newline at end of file
diff --git a/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeChart.jsx b/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeChart.jsx
new file mode 100644
index 0000000..f593c2a
--- /dev/null
+++ b/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeChart.jsx
@@ -0,0 +1,413 @@
+import React, { Component } from 'react';
+import cytoscape from 'cytoscape';
+import cxtmenu from 'cytoscape-cxtmenu'
+import { generateCytoscapeElement } from '../../../features/cypher/CypherUtil'
+import COSEBilkent from 'cytoscape-cose-bilkent';
+
+
+cytoscape.use(COSEBilkent);
+cytoscape.use(cxtmenu);
+
+const getLabel = (ele, captionProp) => {
+  if (captionProp === 'gid') {
+    ele.isNode() ? selectedLabel.node[ele.data('label')] = 'gid' : selectedLabel.edge[ele.data('label')] = 'gid'
+    return "[ " + ele.data('id') + " ]"
+  } else if (captionProp === 'label') {
+    ele.isNode() ? selectedLabel.node[ele.data('label')] = 'label' : selectedLabel.edge[ele.data('label')] = 'label'
+    return "[ :" + ele.data('label') + " ]"
+  } else {
+    const props = ele.data('properties')
+    if (props[captionProp] === undefined) { 
+      ele.isNode() ? selectedLabel.node[ele.data('label')] = 'gid' : selectedLabel.edge[ele.data('label')] = 'gid'
+      return "[ " + ele.data('id') + " ]"
+    }
+    else { 
+      ele.isNode() ? selectedLabel.node[ele.data('label')] = captionProp : selectedLabel.edge[ele.data('label')] = captionProp
+      return props[captionProp] 
+    }
+  }
+
+}
+
+let selectedLabel = {
+  node: {},
+  edge: {}
+}
+
+let initLocation = {}
+
+const stylesheet = [
+  {
+    selector: 'node',
+    style: {
+      width: function (ele) { return ele == null ? 55 : ele.data('size'); },
+      height: function (ele) { return ele == null ? 55 : ele.data('size'); },
+      label: function (ele) { const captionProp = ele.data('caption'); return ele == null ? '' : getLabel(ele, captionProp); },
+      'background-color': function (ele) { return ele == null ? '#FFF' : ele.data('backgroundColor'); },
+      'border-width': "3px",
+      'border-color': function (ele) { return ele == null ? '#FFF' : ele.data('borderColor'); },
+      'border-opacity': 0.6,
+      "text-valign": "center",
+      "text-halign": "center",
+      color: function (ele) { return ele == null ? '#FFF' : ele.data('fontColor'); },
+      "font-size": "10px",
+      "text-wrap": "ellipsis",
+      "text-max-width": function (ele) { return ele == null ? 55 : ele.data('size'); }
+    }
+  },
+  {
+    selector: 'node.highlight',
+    style: {
+      'border-width': "6px",
+      'border-color': "#B2EBF4"
+    }
+  },
+  {
+    selector: 'node:selected',
+    style: {
+      'border-width': "6px",
+      'border-color': "#B2EBF4"
+    }
+  },
+  {
+    selector: 'edge',
+    style: {
+      width: function (ele) { return ele == null ? 1 : ele.data('size'); },
+      label: function (ele) { const captionProp = ele.data('caption'); return ele == null ? '' : getLabel(ele, captionProp); },
+      'text-background-color': '#FFF',
+      'text-background-opacity': 1,
+      'text-background-padding': '3px',
+      'line-color': function (ele) { return ele == null ? '#FFF' : ele.data('backgroundColor'); },
+      'target-arrow-color': function (ele) { return ele == null ? '#FFF' : ele.data('backgroundColor'); },
+      'target-arrow-shape': 'triangle',
+      'curve-style': 'bezier',
+      color: function (ele) { return ele == null ? '#FFF' : ele.data('fontColor'); },
+      "font-size": "10px",
+      "text-rotation": "autorotate"
+    }
+  },
+  {
+    selector: 'edge.highlight',
+    style: {
+      width: function (ele) { return ele == null ? 1 : ele.data('size'); },
+      'line-color': "#B2EBF4",
+      'target-arrow-color': "#B2EBF4",
+      'target-arrow-shape': 'triangle',
+      'curve-style': 'bezier'
+    }
+  },
+  {
+    selector: 'edge:selected',
+    style: {
+      width: function (ele) { return ele == null ? 1 : ele.data('size'); },
+      'line-color': "#B2EBF4",
+      'target-arrow-color': "#B2EBF4",
+      'target-arrow-shape': 'triangle',
+      'curve-style': 'bezier'
+    }
+  }
+]
+
+const coseBilkentLayout = {
+  name: 'cose-bilkent'
+  , idealEdgeLength: 100
+  , nodeDimensionsIncludeLabels: true
+  , fit: true
+  , padding: 10
+  , stop: function (event) {
+    event.cy.nodes().forEach(function (ele) {
+      initLocation[ele.id()] = { x: ele.position().x, y: ele.position().y }
+    });
+  }
+}
+
+const ciseLayout = {
+  name: 'cise',
+  animate: true
+}
+
+const d3Layout = {
+  name: 'd3-force',
+  animate: true, // whether to show the layout as it's running; special 'end' value makes the layout animate like a discrete layout
+  fit: false,
+  fixedAfterDragging: true,
+  linkId: function id(d) {
+    return d.id;
+  },
+  linkDistance: 80,
+  linkStrength: -300,
+  manyBodyStrength: 0,
+  ready: function () { },
+  stop: function (event) {
+    event.cy.nodes().forEach(function (ele) {
+      initLocation[ele.id()] = { x: ele.position().x, y: ele.position().y }
+    });
+  },
+  randomize: true,
+  infinite: false
+  // some more options here...
+}
+
+const conf = {
+  // Common Options
+  style: stylesheet,
+  layout: coseBilkentLayout,
+  // Viewport Options
+  zoom: 1,
+  // Interaction Options
+  minZoom: 0.5,
+  maxZoom: 4,
+  zoomingEnabled: false, //true
+  userZoomingEnabled: false, //true
+  panningEnabled: true,
+  userPanningEnabled: true,
+  boxSelectionEnabled: false, //true
+  selectionType: 'single',
+  touchTapThreshold: 8,
+  desktopTapThreshold: 4,
+  autolock: false,
+  autoungrabify: false,
+  autounselectify: false,
+  // Rendering Options
+  headless: false,
+  styleEnabled: true,
+  hideEdgesOnViewport: false,
+  textureOnViewport: false,
+  motionBlur: false,
+  motionBlurOpacity: 0.2,
+  wheelSensitivity: 1,
+  pixelRatio: 'auto'
+};
+
+
+
+
+class CytoscapeComponent extends Component {
+  constructor(props) {
+    super(props);
+    this.cy = ''
+    this.menu = ''
+    this.addElements = this.addElements.bind(this)
+  }
+
+  closeCxtmenu() {
+    this.menu.destroy()
+  }
+
+  addElements(d) {
+    const generatedData = generateCytoscapeElement( d )
+    if (generatedData.elements.nodes.length === 0) {
+      alert("No data to extend.")
+      return
+    }
+    this.cy.add(generatedData.elements, generatedData.legend)
+    this.cy.layout(coseBilkentLayout).run()
+
+    this.handleUserAction(this.props)
+    this.props.addLegendData(generatedData.legend)
+  }
+
+  handleUserAction(props) {
+    this.cy.elements().bind('mouseover', (e) => {
+      props.onElementsMouseover({ type: 'elements', data: e.target.data() })
+      e.target.addClass('highlight')
+    })
+
+    this.cy.elements().bind('mouseout', (e) => {
+      if (this.cy.elements(':selected').length === 0) {
+        props.onElementsMouseover({ type: 'background', data: { nodeCount: this.cy.nodes().size(), edgeCount: this.cy.edges().size() } })
+      } else {
+        props.onElementsMouseover({ type: 'elements', data: this.cy.elements(':selected')[0].data() })
+      }
+
+      e.target.removeClass('highlight')
+    })
+
+    this.cy.elements().bind('click', (e) => {
+      const ele = e.target
+      this.cy.elements(':selected').unselect()
+      ele.select()
+    })
+
+    this.cy.bind('click', (e) => {
+      if (e.target === this.cy) {
+        props.onElementsMouseover({ type: 'background', data: { nodeCount: this.cy.nodes().size(), edgeCount: this.cy.edges().size() } })
+      }
+    })
+  }
+
+  componentDidMount() {
+    conf.container = this.refs.cyelement;
+    conf.pan = { x: this.refs.cyelement.offsetWidth / 3, y: 50 }
+    let initCy = cytoscape(conf);
+    this.cy = initCy
+
+
+    this.cxtMenuConf = {
+      menuRadius: 75,
+      selector: 'node',
+      commands: [
+        {
+          content: '<span class=""  ><i class="fas fa-lock-open fa-lg"></i></span>',
+          select: function (ele) {
+            ele.animate({ position: initLocation[ele.id()] })
+          }
+        },
+
+        {
+          content: '<span class=""><i class="fas fa-project-diagram fa-lg"></i></span>',
+          select: function (ele) {
+            fetch('/api/v1/cypher',
+              {
+                method: 'POST',
+                headers: {
+                  Accept: 'application/json',
+                  'Content-Type': 'application/json',
+                },
+                body: JSON.stringify({ cmd: 'MATCH (S)-[R]-(T) WHERE id(S) = \'' + ele.id() + '\' RETURN S, R, T' })
+              })
+              .then(res => res.json())
+              .then(data => {
+                this.addElements(data)
+              })
+          }.bind(this)
+        },
+
+        {
+          content: '<span class=""><i class="fas fa-eye-slash fa-lg"></i></span>',
+          select: function (ele) {
+            ele.remove()
+          }
+        },
+
+        {
+          content: '<span class=""><i class="far fa-window-close fa-lg"></i></span>',
+          select: function (ele) {
+          }
+        }
+      ],
+      fillColor: 'rgba(210, 213, 218, 1)',
+      activeFillColor: 'rgba(166, 166, 166, 1)',
+      activePadding: 0,
+      indicatorSize: 0,
+      separatorWidth: 4,
+      spotlightPadding: 3,
+      minSpotlightRadius: 11,
+      maxSpotlightRadius: 99,
+      openMenuEvents: 'click',
+      itemColor: '#2A2C34',
+      itemTextShadowColor: 'transparent',
+      zIndex: 9999,
+      atMouse: false
+    }
+    this.menu = initCy.cxtmenu(this.cxtMenuConf)
+  }
+
+  shouldComponentUpdate() {
+    return false;
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (this.props.elements.nodes.length === 0) {
+      this.cy.add(nextProps.elements)
+      this.cy.layout(coseBilkentLayout).run()
+
+      this.handleUserAction(nextProps)
+
+    } else {
+      if (nextProps.legendData !== undefined) {
+
+        for (const [label, legend] of Object.entries(nextProps.legendData.nodeLegend)) {  
+          this.colorChange('node', label, {color : legend.color, borderColor : legend.borderColor, fontColor : legend.fontColor})
+          this.sizeChange('node', label, legend.size)
+          this.captionChange('node', label, legend.caption)
+        }
+        
+        for (const [label, legend] of Object.entries(nextProps.legendData.edgeLegend)) {
+          this.colorChange('edge', label, {color : legend.color, borderColor : legend.borderColor, fontColor : legend.fontColor})
+          this.sizeChange('edge', label, legend.size)
+          this.captionChange('edge', label, legend.caption)
+        }
+      }
+      this.cy.resize()
+    }
+  }
+
+  componentWillUnmount() {
+    this.menu.destroy()
+    this.cy.destroy()
+  }
+
+
+  resetChart() {
+    this.props.elements.nodes = []
+    this.props.elements.edges = []
+    this.cy.elements().remove()
+  }
+
+  getCaptions(elementType, label) {
+    const eles = this.cy.elements(elementType + '[label = "' + label + '"]').jsons()
+    let extendedSet = new Set([])
+    eles.forEach((ele) => {
+      extendedSet = new Set([...extendedSet, ...Object.keys(ele.data.properties)])
+    })
+    return extendedSet
+  }
+
+  getCurrecntCaption(elementType, label) {
+    if (elementType === 'edge' && selectedLabel[elementType][label] === undefined) {
+      selectedLabel[elementType][label] = 'label'
+    }
+
+    return selectedLabel[elementType][label]
+  }
+
+  getCy() {
+    return this.cy;
+  }
+
+  colorChange(elementType, label, color) {
+    let c = {}
+
+    if (Array.isArray(color)) {
+      c['color'] = color[0]
+      c['borderColor'] = color[1]
+      c['fontColor'] = color[2]
+    } else {
+      c = color
+    }
+
+    if (elementType === 'node') {
+      this.cy.nodes('[label = "' + label + '"]').data("backgroundColor", c.color).data("borderColor", c.borderColor).data("fontColor", c.fontColor)
+    } else if (elementType === 'edge') {
+      this.cy.edges('[label = "' + label + '"]').data("backgroundColor", c.color).data("fontColor", c.fontColor)
+    }
+
+  }
+
+  sizeChange(elementType, label, size) {
+    const changedData = this.cy.elements(elementType + '[label = "' + label + '"]').data("size", size)
+
+    if (size > 6) {
+      changedData.style('text-background-opacity', 0)
+    } else {
+      changedData.style('text-background-opacity', 1)
+    }
+  }
+
+  captionChange(elementType, label, caption) {
+    if (caption === 'gid') {
+      this.cy.elements(elementType + '[label = "' + label + '"]').style('label', function (ele) { return ele == null ? '' : "[ " + ele.data('id') + " ]"; })
+    } else if (caption === 'label') {
+      this.cy.elements(elementType + '[label = "' + label + '"]').style('label', function (ele) { return ele == null ? '' : "[ :" + ele.data('label') + " ]"; })
+    } else {
+      this.cy.elements(elementType + '[label = "' + label + '"]').style('label', function (ele) { return ele == null ? '' : (ele.data('properties')[caption] == null ? '' : ele.data('properties')[caption]) })
+    }
+  }
+
+  render() {
+    return <div id="cyto" className="chart-area" ref="cyelement" />
+  }
+}
+
+export default CytoscapeComponent;
\ No newline at end of file
diff --git a/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeFooter.jsx b/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeFooter.jsx
new file mode 100644
index 0000000..4723484
--- /dev/null
+++ b/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeFooter.jsx
@@ -0,0 +1,93 @@
+import React, {useState} from 'react';
+import { Badge } from 'react-bootstrap'
+import uuid from 'react-uuid'
+import { updateLabelColor, updateNodeLabelSize, updateEdgeLabelSize, updateLabelCaption } from '../../../features/cypher/CypherUtil'
+
+const CypherResultCytoscapeFooter = ({ footerData, labelColors, nodeLabelSizes, edgeLabelSizes, colorChange, sizeChange, captionChange }) => {
+  const extractData = (d) => {
+    let extractedData = []
+    for (const [alias, val] of Object.entries(d)) {
+      extractedData.push(<span key={uuid()} className="label"><strong className="pl-3">{alias} : </strong> {val}</span>)
+    }
+    return extractedData
+  }
+  
+  const displayFooterData = () => {
+
+    if (footerData.type === 'elements') {
+      const isEdge = footerData.data.source ? {} : { pill: true }
+
+      return (
+        <div className="pl-3">
+          <Badge className="px-3 py-1" {...isEdge} style={{ backgroundColor: footerData.data.backgroundColor, color: footerData.data.fontColor }}>{footerData.data.label}</Badge>
+          <span className="label"><strong className="pl-3">&lt;gid&gt; : </strong> {footerData.data.id}</span>
+          {extractData(footerData.data.properties)}
+        </div>
+      )
+
+    } else if (footerData.type === 'background') {
+      return <span className="label pl-3">Displaying <strong>{footerData.data.nodeCount}</strong> nodes, <strong>{footerData.data.edgeCount}</strong> edges</span>
+    } else if (footerData.type === 'labels') {
+      const isEdge = footerData.data.type === 'edge' ? {} : { pill: true }
+
+
+      const generateButton = () => {
+          if (footerData.data.type === 'node') {
+            return nodeLabelSizes.map((labelSize, i) => {
+              return nodeSizeButton(labelSize.size, i)
+            })
+          } else if (footerData.data.type === 'edge') {
+            return edgeLabelSizes.map((labelSize, i) => {
+              return edgeSizeButton(labelSize.size, i)
+            })
+          }           
+      }
+      
+      const nodeSizeButton = (nodeSize, i) => {
+        let size = (i * 3) + 12; 
+        return <button onClick={() => [updateNodeLabelSize(footerData.data.label, nodeSize), sizeChange(footerData.data.type, footerData.data.label, nodeSize)]} 
+        key={uuid()} 
+        type="button" 
+        className={"btn sizeSelector node " + (footerData.data.size >= nodeSize ? " selectedSize " : "")} 
+        style={{width: size+'px', height: size+'px'}} />
+      }
+
+      const edgeSizeButton = (edgeSize, i) => {
+        let size = (i * 3) + 12; 
+        return <button onClick={() => [updateEdgeLabelSize(footerData.data.label, edgeSize), sizeChange(footerData.data.type, footerData.data.label, edgeSize)]} 
+        key={uuid()} 
+        type="button" 
+        className={"btn sizeSelector edge " + (footerData.data.size >= edgeSize ? " selectedSize " : "")} 
+        style={{width: size+18+'px', height: size+'px'}} />
+      }
+
+      return (
+        <div className="pl-3">
+          <Badge className="px-3 py-1" {...isEdge} style={{ backgroundColor: footerData.data.backgroundColor, color: footerData.data.fontColor }}>{footerData.data.label}</Badge>
+          <span className="label">
+            <span className="pl-3">Color : </span> 
+            {labelColors.map((color)=>{return <button onClick={() => [updateLabelColor(footerData.data.label, color), colorChange(footerData.data.type, footerData.data.label, color)]} key={uuid()} type="button" className={"btn colorSelector " + (footerData.data.backgroundColor === color.color ? " selectedColor " : "")} style={{backgroundColor:color.color}}></button> })}
+          </span>
+          <span className="label">
+            <span className="pl-3">Size : </span> 
+            {generateButton()}
+          </span>
+          <span className="label">
+            <span className="pl-3">Caption : </span> 
+            {footerData.data.captions.map((caption) => {
+              return <button onClick={() => [updateLabelCaption(footerData.data.type, footerData.data.label, caption), captionChange(footerData.data.type, footerData.data.label, caption)]} key={uuid()} type="button" class={"btn captionSelector " + (footerData.data.selectedCaption === caption ? " btn-secondary " : " btn-outline-dark ")}><strong>&lt;{caption}&gt;</strong></button>
+            })}
+
+          </span>
+        </div>
+      )
+    }
+  }
+
+  return <div className="chart-footer-area text-muted">
+    {displayFooterData()}
+  </div>
+}
+
+
+export default CypherResultCytoscapeFooter
\ No newline at end of file
diff --git a/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeLegend.jsx b/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeLegend.jsx
index 07145ea..3155f2f 100644
--- a/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeLegend.jsx
+++ b/frontend/src/components/cypherresult/presentations/CypherResultCytoscapeLegend.jsx
@@ -1,30 +1,71 @@
-import React from 'react';
-import {Badge} from 'react-bootstrap'
+import React, { Component } from 'react';
+import { Badge } from 'react-bootstrap'
+import uuid from 'react-uuid'
 
-const CypherResultCytoscapeLegend = ({legendData}) => {
-  const {nodeLegend, edgeLegend} = legendData
-
-  const nodeBadges = []
-  const edgeBadges = []
-
-
-  for (const [label, color] of Object.entries(nodeLegend)) {
-    nodeBadges.push(<Badge className="px-3 mx-1" pill key={label} style={{ backgroundColor : color, fontSize : '0.9rem' }}>{label}</Badge>)
+class CypherResultCytoscapeLegend extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      nodeBadges: new Map(),
+      edgeBadges: new Map()
+    }
   }
 
-  for (const [label, color] of Object.entries(edgeLegend)) {
-    edgeBadges.push(<Badge className="px-3 mx-1" key={label} style={{ backgroundColor : color, fontSize : '0.9rem' }}>{label}</Badge>)
+  componentDidMount() {
   }
-  
-    return <div className="legend-area pt-2" style={{ width: '100%', height:'50px', position:'absolute', 'zIndex':100}}>
-      <div className="nodeLegend" style={{ width: '100%' }}>
-      {nodeBadges}
+
+  shouldComponentUpdate() {
+    return true;
+  }
+
+  componentWillReceiveProps(nextProps) {
+    let newNodeBadges = this.state.nodeBadges
+    let newEdgeBadges = this.state.edgeBadges
+    if (nextProps.isReloading) {
+      newNodeBadges =  new Map()
+      newEdgeBadges =  new Map()
+    }
+
+    for (const [label, legend] of Object.entries(nextProps.legendData.nodeLegend)) {       
+      newNodeBadges.set(label, <Badge className="nodeLabel px-3 py-2 mx-1 my-2" pill key={uuid()} onClick={() => nextProps.onLabelClick({ type: 'labels', data: { type: 'node', backgroundColor: legend.color, fontColor: legend.fontColor, size: legend.size, label: label } })} style={{ backgroundColor: legend.color, color: legend.fontColor }}>{label}</Badge>)
+    }
+    
+    for (const [label, legend] of Object.entries(nextProps.legendData.edgeLegend)) {
+      newEdgeBadges.set(label, <Badge className="edgeLabel px-3 py-2 mx-1 my-2" key={uuid()} onClick={() => nextProps.onLabelClick({ type: 'labels', data: { type: 'edge', backgroundColor: legend.color, fontColor: legend.fontColor, size: legend.size, label: label } })} style={{ backgroundColor: legend.color, color: legend.fontColor }}>{label}</Badge>)
+    }
+
+    this.setState({nodeBadges : newNodeBadges})
+    this.setState({edgeBadges : newEdgeBadges})
+
+
+  }
+
+  componentWillUnmount() {
+  }
+
+
+  render() {
+    let nodeLedgend = []
+    let edgeLedgend = []
+
+    this.state.nodeBadges.forEach((value, key, mapObj) => {
+      return nodeLedgend.push(value)
+    })
+
+    this.state.edgeBadges.forEach((value, key, mapObj) => {
+      return edgeLedgend.push(value)
+    })
+
+    return <div className="legend-area" style={{ width: '100%' }}>
+      <div className="nodeLegend">
+        {nodeLedgend}
       </div>
-      <div className="edgeLegend" style={{ width: '100%' }}>
-      {edgeBadges}
+      <div className="edgeLegend">
+        {edgeLedgend}
       </div>
+
     </div>
+  }
 }
+export default CypherResultCytoscapeLegend
 
-
-export default CypherResultCytoscapeLegend
\ No newline at end of file
diff --git a/frontend/src/components/cypherresult/presentations/CypherResultTable.jsx b/frontend/src/components/cypherresult/presentations/CypherResultTable.jsx
index 116dc8b..c54e50e 100644
--- a/frontend/src/components/cypherresult/presentations/CypherResultTable.jsx
+++ b/frontend/src/components/cypherresult/presentations/CypherResultTable.jsx
@@ -1,7 +1,13 @@
 import React from 'react';
 import Table from 'react-bootstrap/Table'
 const CypherResultTable = ({data}) => {
-    return (
+  console.log("????????????", data)
+    if (data.command && data.command.toUpperCase() === 'GRAPH') {
+      return <span style={{margin:'25px'}}>Affected {data.rowCount === null ? 0 : data.rowCount} </span>
+    
+    
+  } else {
+    return (      
       <Table className="table table-hover">
         <thead>
           <tr >
@@ -24,6 +30,7 @@
         </tbody>
       </Table>
     )
+  }
 
 }
 
diff --git a/frontend/src/components/frame/containers/CypherDmlResultContainers.js b/frontend/src/components/frame/containers/CypherDmlResultContainers.js
new file mode 100644
index 0000000..8e41b68
--- /dev/null
+++ b/frontend/src/components/frame/containers/CypherDmlResultContainers.js
@@ -0,0 +1,12 @@
+import {connect} from 'react-redux'
+import {removeFrame} from '../../../features/frame/FrameSlice'
+import CypherDmlResultFrame from '../presentations/CypherDmlResultFrame'
+
+const mapStateToProps = (state) => {
+    return {
+    }
+}
+
+const mapDispatchToProps = { removeFrame }
+
+export default connect(mapStateToProps, mapDispatchToProps)(CypherDmlResultFrame);
diff --git a/frontend/src/components/frame/containers/CypherMatchResultContainers.js b/frontend/src/components/frame/containers/CypherMatchResultContainers.js
new file mode 100644
index 0000000..5bb06f5
--- /dev/null
+++ b/frontend/src/components/frame/containers/CypherMatchResultContainers.js
@@ -0,0 +1,12 @@
+import {connect} from 'react-redux'
+import {removeFrame} from '../../../features/frame/FrameSlice'
+import CypherMatchResultFrame from '../presentations/CypherMatchResultFrame'
+
+const mapStateToProps = (state) => {
+    return {
+    }
+}
+
+const mapDispatchToProps = { removeFrame }
+
+export default connect(mapStateToProps, mapDispatchToProps)(CypherMatchResultFrame);
diff --git a/frontend/src/components/frame/containers/CypherResultContainers.js b/frontend/src/components/frame/containers/CypherResultContainers.js
deleted file mode 100644
index dd2ca92..0000000
--- a/frontend/src/components/frame/containers/CypherResultContainers.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import {connect} from 'react-redux'
-import {executeCypherQuery} from '../../../features/cypher/CypherSlice'
-import {removeFrame} from '../../../features/frame/FrameSlice'
-import CypherResultFrame from '../presentations/CypherResultFrame'
-
-const mapStateToProps = (state) => {
-    return {
-    }
-}
-
-const mapDispatchToProps = { executeCypherQuery, removeFrame }
-
-export default connect(mapStateToProps, mapDispatchToProps)(CypherResultFrame);
diff --git a/frontend/src/components/frame/containers/ServerConnectContainer.js b/frontend/src/components/frame/containers/ServerConnectContainer.js
index 47b7cdf..2a4e834 100644
--- a/frontend/src/components/frame/containers/ServerConnectContainer.js
+++ b/frontend/src/components/frame/containers/ServerConnectContainer.js
@@ -1,5 +1,6 @@
 import {connect} from 'react-redux'
 import {connectToAgensGraph} from '../../../features/database/DatabaseSlice'
+import {getMetaData} from '../../../features/database/MetadataSlice'
 import {removeFrame} from '../../../features/frame/FrameSlice'
 import {addAlert} from '../../../features/alert/AlertSlice'
 import ServerConnectFrame from '../presentations/ServerConnectFrame'
@@ -9,7 +10,7 @@
     }
 }
 
-const mapDispatchToProps = { connectToAgensGraph, removeFrame, addAlert }
+const mapDispatchToProps = { connectToAgensGraph, removeFrame, addAlert, getMetaData }
 
 
 export default connect(mapStateToProps, mapDispatchToProps)(ServerConnectFrame);
diff --git a/frontend/src/components/frame/presentations/CypherResultFrame.jsx b/frontend/src/components/frame/presentations/CypherDmlResultFrame.jsx
similarity index 67%
copy from frontend/src/components/frame/presentations/CypherResultFrame.jsx
copy to frontend/src/components/frame/presentations/CypherDmlResultFrame.jsx
index 2ed56ad..6f05e7c 100644
--- a/frontend/src/components/frame/presentations/CypherResultFrame.jsx
+++ b/frontend/src/components/frame/presentations/CypherDmlResultFrame.jsx
@@ -1,5 +1,6 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, createRef } from 'react';
 import { useDispatch } from 'react-redux'
+import uuid from 'react-uuid'
 import { Tab, Nav, Collapse } from 'react-bootstrap';
 import CypherResultCytoscapeContainer from '../../cypherresult/containers/CypherResultCytoscapeContainer'
 import CypherResultTableContainer from '../../cypherresult/containers/CypherResultTableContainer'
@@ -7,28 +8,27 @@
 import CypherResultMetaContainer from '../../cypherresult/containers/CypherResultMetaContainer'
 
 const CypherResultFrame = ({ refKey, reqString, removeFrame, executeCypherQuery }) => {
+    const chartAreaRef = createRef()
     const [isExpanded, setIsExpanded] = useState(true)
+    const [isFullScreen, setIsFullScreen] = useState(false)
+    
+    const expandFrame = () => {       
+        setIsFullScreen(!isFullScreen)
+    }
 
-    const dispatch = useDispatch();
-
-    useEffect(() => {
-        dispatch(() => executeCypherQuery([refKey, reqString]));
-    }, [refKey, reqString, executeCypherQuery, dispatch])
 
     return (
-        <div className="card mt-3">
+        <div className={"card " + (isFullScreen ? " fullscreen " : "mt-3")}>
             <div className="card-header">
                 <div className="d-flex card-title text-muted">
                     <div className="mr-auto"><strong> $ {reqString} </strong></div>
-                    <button className="frame-head-button btn btn-link px-3"><span className="fa fa-download fa-lg"
-                        aria-hidden="true"></span></button>
+                    <button className="frame-head-button btn btn-link px-3">
+                        <span className="fa fa-expand fa-lg" aria-hidden="true" onClick={() => expandFrame()}></span></button>
                     <button className="frame-head-button btn btn-link px-3"><span className="fa fa-paperclip fa-lg"
                         aria-hidden="true"></span></button>
                     <button className="frame-head-button btn btn-link px-3" data-toggle="collapse"
                         aria-expanded={isExpanded} onClick={() => setIsExpanded(!isExpanded)} aria-controls={refKey}>
                         <span className="fa fa-lg" aria-hidden="true"></span></button>
-                    <button className="frame-head-button btn btn-link px-3">
-                        <span className="fa fa-refresh fa-lg" aria-hidden="true"></span></button>
                     <button className="frame-head-button btn btn-link pl-3">
                         <span className="fa fa-times fa-lg" aria-hidden="true" onClick={() => removeFrame(refKey)}></span></button>
                 </div>
@@ -36,41 +36,25 @@
             <Collapse in={isExpanded}>
             <div className="card-body card-body-graph collapse" id={refKey}>
                 <div className="d-flex h-100">
-                    <Tab.Container defaultActiveKey="graph">
+                    <Tab.Container defaultActiveKey="table">
 
                         <Nav variant="pills" className="flex-column graph-card-nav">
 
                             <Nav.Item>
-                                <Nav.Link eventKey="graph"><span className="fa fa-paperclip" aria-hidden="true"></span><br />Graph</Nav.Link>
-                            </Nav.Item>
-
-                            <Nav.Item>
                                 <Nav.Link eventKey="table"><span className="fa fa-table" aria-hidden="true"></span><br />Table</Nav.Link>
                             </Nav.Item>
 
                             <Nav.Item>
-                                <Nav.Link eventKey="text"><span className="fa fa-font" aria-hidden="true"></span><br />Text</Nav.Link>
-                            </Nav.Item>
-
-                            <Nav.Item>
                                 <Nav.Link eventKey="code"><span className="fa fa-terminal" aria-hidden="true"></span><br />Meta</Nav.Link>
                             </Nav.Item>
 
                         </Nav>
-                        <Tab.Content className="graph-card-content container-fluid" >
-
-                            <Tab.Pane eventKey="graph" style={{ height: '100%' }}>
-                                <CypherResultCytoscapeContainer refKey={refKey} />
-                            </Tab.Pane>
+                        <Tab.Content className="graph-card-content container-fluid graph-tabpanel">
 
                             <Tab.Pane eventKey="table">
                                 <CypherResultTableContainer refKey={refKey} />
                             </Tab.Pane>
 
-                            <Tab.Pane eventKey="text">
-                                <CypherResultTextContainer refKey={refKey} />
-                            </Tab.Pane>
-
                             <Tab.Pane eventKey="code">
                                 <CypherResultMetaContainer refKey={refKey} />
                             </Tab.Pane>
diff --git a/frontend/src/components/frame/presentations/CypherResultFrame.jsx b/frontend/src/components/frame/presentations/CypherMatchResultFrame.jsx
similarity index 71%
rename from frontend/src/components/frame/presentations/CypherResultFrame.jsx
rename to frontend/src/components/frame/presentations/CypherMatchResultFrame.jsx
index 2ed56ad..ca35bca 100644
--- a/frontend/src/components/frame/presentations/CypherResultFrame.jsx
+++ b/frontend/src/components/frame/presentations/CypherMatchResultFrame.jsx
@@ -1,5 +1,6 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, createRef } from 'react';
 import { useDispatch } from 'react-redux'
+import uuid from 'react-uuid'
 import { Tab, Nav, Collapse } from 'react-bootstrap';
 import CypherResultCytoscapeContainer from '../../cypherresult/containers/CypherResultCytoscapeContainer'
 import CypherResultTableContainer from '../../cypherresult/containers/CypherResultTableContainer'
@@ -7,28 +8,56 @@
 import CypherResultMetaContainer from '../../cypherresult/containers/CypherResultMetaContainer'
 
 const CypherResultFrame = ({ refKey, reqString, removeFrame, executeCypherQuery }) => {
+    const chartAreaRef = createRef()
     const [isExpanded, setIsExpanded] = useState(true)
+    const [isFullScreen, setIsFullScreen] = useState(false)
+    const [zoomRate, setZoomRate] = useState(0)
+    const [pan, setPan] = useState({x : 0, y : 0})
+    const [cyZoomingEnabled, setCyZoomingEnabled] = useState(false)
+    const [cytoscapeContainerKey, setCytoscapeContainerKey] = useState(uuid())
 
     const dispatch = useDispatch();
 
     useEffect(() => {
-        dispatch(() => executeCypherQuery([refKey, reqString]));
+        //dispatch(() => executeCypherQuery([refKey, reqString]));       
+        setZoomRate(chartAreaRef.current.getCy().zoom())
+        setPan(chartAreaRef.current.getCy().pan())
     }, [refKey, reqString, executeCypherQuery, dispatch])
 
+    
+    const expandFrame = () => {       
+        setIsFullScreen(!isFullScreen)
+        setCyZoomingEnabled(!cyZoomingEnabled)
+        const ref = chartAreaRef.current
+        window.setTimeout(resize, 500)
+        function resize() {
+            ref.getCy().resize()           
+            ref.getCy().zoom({level : zoomRate, position: { x: 0, y: 0 }})
+            ref.getCy().zoomingEnabled(!cyZoomingEnabled)
+            ref.getCy().userZoomingEnabled(!cyZoomingEnabled)
+        }
+    }
+
+    const refreshFrame = () => {
+        setCytoscapeContainerKey(uuid())
+    }
+
     return (
-        <div className="card mt-3">
+        <div className={"card " + (isFullScreen ? " fullscreen " : "mt-3")}>
             <div className="card-header">
                 <div className="d-flex card-title text-muted">
                     <div className="mr-auto"><strong> $ {reqString} </strong></div>
                     <button className="frame-head-button btn btn-link px-3"><span className="fa fa-download fa-lg"
                         aria-hidden="true"></span></button>
+                    <button className="frame-head-button btn btn-link px-3">
+                        <span className="fa fa-expand fa-lg" aria-hidden="true" onClick={() => expandFrame()}></span></button>
+                    <button className="frame-head-button btn btn-link px-3">
+                        <span className="fa fa-refresh fa-lg" aria-hidden="true" onClick={() => refreshFrame()}></span></button>
                     <button className="frame-head-button btn btn-link px-3"><span className="fa fa-paperclip fa-lg"
                         aria-hidden="true"></span></button>
                     <button className="frame-head-button btn btn-link px-3" data-toggle="collapse"
                         aria-expanded={isExpanded} onClick={() => setIsExpanded(!isExpanded)} aria-controls={refKey}>
                         <span className="fa fa-lg" aria-hidden="true"></span></button>
-                    <button className="frame-head-button btn btn-link px-3">
-                        <span className="fa fa-refresh fa-lg" aria-hidden="true"></span></button>
                     <button className="frame-head-button btn btn-link pl-3">
                         <span className="fa fa-times fa-lg" aria-hidden="true" onClick={() => removeFrame(refKey)}></span></button>
                 </div>
@@ -57,10 +86,10 @@
                             </Nav.Item>
 
                         </Nav>
-                        <Tab.Content className="graph-card-content container-fluid" >
+                        <Tab.Content className="graph-card-content container-fluid graph-tabpanel">
 
                             <Tab.Pane eventKey="graph" style={{ height: '100%' }}>
-                                <CypherResultCytoscapeContainer refKey={refKey} />
+                                <CypherResultCytoscapeContainer key={cytoscapeContainerKey} forwardedRef={chartAreaRef} refKey={refKey} isFullScreen={isFullScreen} />
                             </Tab.Pane>
 
                             <Tab.Pane eventKey="table">
diff --git a/frontend/src/components/frame/presentations/ServerConnectFrame.jsx b/frontend/src/components/frame/presentations/ServerConnectFrame.jsx
index a96d14f..9e37067 100644
--- a/frontend/src/components/frame/presentations/ServerConnectFrame.jsx
+++ b/frontend/src/components/frame/presentations/ServerConnectFrame.jsx
@@ -1,7 +1,7 @@
 import React, {useState} from 'react'
 import {Collapse} from 'react-bootstrap'
 
-const ServerConnectFrame = ({refKey, reqString, connectToAgensGraph, removeFrame, addAlert}) => {
+const ServerConnectFrame = ({refKey, reqString, connectToAgensGraph, removeFrame, addAlert, getMetaData}) => {
     const [formData, setFormData] = useState({})
     const [isExpanded, setIsExpanded] = useState(true)
 
@@ -66,7 +66,7 @@
                             </fieldset>
                             
                         </form>
-                        <button className="btn btn-info" onClick={() => [connectToAgensGraph(formData), addAlert('NoticeServerConnected')]}>CONNECT</button>
+                        <button className="btn btn-info" onClick={() => [connectToAgensGraph(formData), addAlert('NoticeServerConnected'), getMetaData()]}>CONNECT</button>
                     </div>
                 </div>
             </div>
diff --git a/frontend/src/components/navigator/presentations/NavigatorItem.jsx b/frontend/src/components/navigator/presentations/NavigatorItem.jsx
index 637c3f4..6115895 100644
--- a/frontend/src/components/navigator/presentations/NavigatorItem.jsx
+++ b/frontend/src/components/navigator/presentations/NavigatorItem.jsx
@@ -5,7 +5,7 @@
     return (
         <li className="nav-item">
             <a id={"side-"+ menuName + "-tab"} className={"nav-link" + (activeMenuName === menuName ? " active show " : "") } data-classname="fixed-left" data-toggle="pill"
-                href="/#" role="tab" aria-controls={"side-" + menuName} aria-selected="true" onClick={() => onClick(activeMenuName, menuName)}><i
+                href="/#" role="tab" aria-controls={"side-" + menuName} aria-selected="true" onClick={() => onClick(menuName)}><i
                     className={"fa fa-" + fwCode}></i></a>
         </li>
     );
diff --git a/frontend/src/components/sidebar/containers/Sidebar.js b/frontend/src/components/sidebar/containers/Sidebar.js
index 78f52fb..9da84ef 100644
--- a/frontend/src/components/sidebar/containers/Sidebar.js
+++ b/frontend/src/components/sidebar/containers/Sidebar.js
@@ -4,7 +4,11 @@
 
 const mapStateToProps = (state) => {
     return {
-        activeMenuName: state.navigator.activeMenu
+        activeMenuName: state.navigator.activeMenu,
+        isActive: state.navigator.isActive,
+        edges : state.metadata.edges,
+        nodes : state.metadata.nodes,
+        propertyKeys : state.metadata.propertyKeys
     }
 }
 
diff --git a/frontend/src/components/sidebar/presentations/Sidebar.jsx b/frontend/src/components/sidebar/presentations/Sidebar.jsx
index a9c645c..475e612 100644
--- a/frontend/src/components/sidebar/presentations/Sidebar.jsx
+++ b/frontend/src/components/sidebar/presentations/Sidebar.jsx
@@ -2,19 +2,18 @@
 import SidebarHome from './SidebarHome'
 import SidebarSetting from './SidebarSetting'
 
-
-const Sidebar = ({ activeMenuName, changeTheme }) => {
-    return (        
-        <div id="sidebar" className={activeMenuName !== "" ? " active " : ""}>
-                <div className="tab-content">
-                    <div className={"tab-pane fade" + (activeMenuName === "home" ? " active show " : "") } role="tabpanel" aria-labelledby="side-home-tab">
-                        <SidebarHome />
-                    </div>
-                    <div className={"tab-pane fade" + (activeMenuName === "setting" ? " active show " : "") } role="tabpanel" aria-labelledby="side-setting-tab">
-                        <SidebarSetting changeTheme={changeTheme} />
-                    </div>
+const Sidebar = ({ activeMenuName, isActive, changeTheme, edges, nodes, propertyKeys }) => {
+    return (
+        <div id="sidebar" className={isActive ? " active " : ""} style={{overflowY: 'scroll'}}>
+            <div className="tab-content">
+                <div className={"tab-pane fade" + (activeMenuName === "home" ? " active show " : "") } role="tabpanel" aria-labelledby="side-home-tab">
+                    <SidebarHome edges={edges} nodes={nodes} propertyKeys={propertyKeys} />
+                </div>
+                <div className={"tab-pane fade" + (activeMenuName === "setting" ? " active show " : "") } role="tabpanel" aria-labelledby="side-setting-tab">
+                    <SidebarSetting changeTheme={changeTheme} />
                 </div>
             </div>
+        </div>
     );
 }
 
diff --git a/frontend/src/components/sidebar/presentations/SidebarHome.jsx b/frontend/src/components/sidebar/presentations/SidebarHome.jsx
index 1b23701..6cc4ea8 100644
--- a/frontend/src/components/sidebar/presentations/SidebarHome.jsx
+++ b/frontend/src/components/sidebar/presentations/SidebarHome.jsx
@@ -1,13 +1,150 @@
-import React from 'react'
+import React, { useReducer } from 'react'
+import { Badge } from 'react-bootstrap'
+import { Fragment } from 'react';
+import uuid from 'react-uuid';
 
-const SidebarHome = () => {
+const ColoredLine = () => (
+    <hr
+        style={{
+            color: '#B0B0B0',
+            backgroundColor: '#B0B0B0',
+            marginTop: 0,
+            height: 0.3
+        }}
+    />
+);
+
+const NodeList = ({nodes}) => {
+    let list;
+    if(nodes) {
+        list = nodes.map(item => (
+            <NodeItems
+                key={uuid()}
+                label={item.label}
+                cnt={item.cnt}
+            />
+        ));
+        return (
+            <div style={{display: 'flex', flexWrap: 'wrap'}}>
+                {list}
+            </div>
+        )
+    }
+    else {
+        return null;
+    }
+};
+
+const NodeItems = ({label, cnt}) => (
+    <Fragment>
+        <h5 style={{paddingRight: '0.3em'}}><span className="badge badge-pill badge-light">{label}({cnt})</span></h5>
+    </Fragment>
+);
+
+const EdgeList = ({edges}) => {
+    let list;
+    if(edges) {
+        list = edges.map(item => (
+            <EdgeItems
+                key={uuid()}
+                label={item.label}
+                cnt={item.cnt}
+            />
+        ));
+        return (
+        <div style={{display: 'flex', flexWrap: 'wrap'}}>
+            {list}
+        </div>
+        )
+    }
+    else {
+        return null;
+    }
+};
+
+const EdgeItems = ({label, cnt}) => (
+    <Fragment>
+        <h5 style={{paddingRight: '0.3em'}}><span className="badge badge-light">{label}({cnt})</span></h5>
+    </Fragment>
+);
+
+const PropertyList = ({propertyKeys}) => {
+    let list;
+    if(propertyKeys) {
+        list = propertyKeys.map(item => (
+            <PropertyItems
+                key={uuid()}
+                propertyName={item.key}
+                classNames={item.key_type === 'v' ? 'badge badge-dark' : 'badge badge-light'}
+            />
+        ));
+        return (
+        <div style={{display: 'flex', flexWrap: 'wrap'}}>
+            {list}
+        </div>
+        )
+    }
+    else {
+        return null;
+    }
+};
+
+const PropertyItems =({propertyName, classNames}) => (
+    <Fragment>
+        <h5 style={{paddingRight: '0.3em'}}><span className={classNames}>{propertyName}</span></h5>
+    </Fragment>
+);
+
+const ConnectedText =() => (
+    <div>
+        <h6><div className="col-sm-6" style={{textAlign:'right'}}>Username:</div><div className="col-sm-6"></div></h6>
+        <h6><div className="col-sm-6" style={{textAlign:'right'}}>Roles:</div><div className="col-sm-6"></div></h6>
+    </div>
+);
+
+const DBMSText =() => (
+    <div>
+        <h6><div className="col-sm-6" style={{textAlign:'right'}}>Version:</div><div className="col-sm-6"></div></h6>
+        <h6><div className="col-sm-6" style={{textAlign:'right'}}>Edition:</div><div className="col-sm-6"></div></h6>
+        <h6><div className="col-sm-6" style={{textAlign:'right'}}>Name:</div><div className="col-sm-6"></div></h6>
+        <h6><div className="col-sm-6" style={{textAlign:'right'}}>Databases:</div><div className="col-sm-6"></div></h6>
+        <h6><div className="col-sm-6" style={{textAlign:'right'}}>Information:</div><div className="col-sm-6"></div></h6>
+        <h6><div className="col-sm-6" style={{textAlign:'right'}}>Query List:</div><div className="col-sm-6"></div></h6>
+    </div>
+);
+
+const SidebarHome = ({edges, nodes, propertyKeys}) => {
     return (
         <div className="sidebar-home">
             <div className="sidebar sidebar-header">
-                <h3>HOME</h3>
+                <h3>Database Information</h3>
             </div>
             <div className="sidebar sidebar-body">
-                Content....
+                <div className="form-group">
+                    <label htmlFor="exampleFormControlSelect1"><b>Vertex Label</b></label>
+                    <ColoredLine />
+                    <NodeList nodes={nodes} />
+                </div>
+                <div className="form-group">
+                    <label htmlFor="exampleFormControlSelect1"><b>Edge Label</b></label>
+                    <ColoredLine />
+                    <EdgeList edges={edges} />
+                </div>
+                <div className="form-group">
+                    <label htmlFor="exampleFormControlSelect1"><b>Properties</b></label>
+                    <ColoredLine />
+                    <PropertyList propertyKeys={propertyKeys} />
+                </div>
+                <div className="form-group">
+                    <label htmlFor="exampleFormControlSelect1"><b>Connected as</b></label>
+                    <ColoredLine />
+                    <ConnectedText />
+                </div>
+                <div className="form-group">
+                    <label htmlFor="exampleFormControlSelect1"><b>DBMS</b></label>
+                    <ColoredLine />
+                    <DBMSText />
+                </div>
             </div>
         </div>
     );
diff --git a/frontend/src/features/cypher/CypherSlice.js b/frontend/src/features/cypher/CypherSlice.js
index 6441ace..b053c3f 100644
--- a/frontend/src/features/cypher/CypherSlice.js
+++ b/frontend/src/features/cypher/CypherSlice.js
@@ -3,48 +3,65 @@
 export const executeCypherQuery = createAsyncThunk(
   'cypher/executeCypherQuery',
   async (args) => {
-    const response = await fetch('/api/v1/cypher', 
-    {
-      method: 'POST',
-      headers: {
+    const response = await fetch('/api/v1/cypher',
+      {
+        method: 'POST',
+        headers: {
           Accept: 'application/json',
           'Content-Type': 'application/json',
-      },
-      body: JSON.stringify({cmd: args[1]})
-    })
+        },
+        body: JSON.stringify({ cmd: args[1] })
+      })
     if (response.ok) {
-      const resData = {}
-      resData['key'] = args[0];
-      resData['query'] = args[1];
-      const res = await response.json();     
-      resData['data'] = res['data']
-      return resData;
+      const res = await response.json();
+      return Object.assign({key : args[0], query : args[1], ...res})
     } else {
       alert("Connection Error")
       return {};
     }
   }
 
-  
+
 )
 
 const CypherSlice = createSlice({
   name: 'cypher',
   initialState: {
-    queryResult : {}
+    queryResult: {},
+    labels: { nodeLabels : {}, edgeLabels : {} }
   },
   reducers: {
+    setLabels: {
+      reducer: (state, action) => {
+        if (action.payload.elementType === 'node') {
+          if (state.labels.nodeLabels[action.payload.label] === undefined ) {state.labels.nodeLabels[action.payload.label] = action.payload.property} 
+          else {Object.assign(state.labels.nodeLabels[action.payload.label], action.payload.property)} 
+          
+        } else if (action.payload.elementType === 'edge') {
+          if (state.labels.edgeLabels[action.payload.label] === undefined ) {state.labels.edgeLabels[action.payload.label] = action.payload.property} 
+          else {Object.assign(state.labels.edgeLabels[action.payload.label], action.payload.property)} 
+        }
+        
+      },
+      prepare: (elementType, label, property) => {
+        return { payload: { elementType, label, property } }
+      }
+    }
   },
   extraReducers: {
     [executeCypherQuery.pending]: (state, action) => {
     },
     [executeCypherQuery.fulfilled]: (state, action) => {
       state.queryResult[action.payload.key] = {}
-      state.queryResult[action.payload.key].response = action.payload
+      //state.queryResult[action.payload.key].response = action.payload
+      Object.assign(state.queryResult[action.payload.key], action.payload)
     },
     [executeCypherQuery.rejectd]: (state, action) => {
     }
   }
 })
 
+
+export const { setLabels } = CypherSlice.actions
+
 export default CypherSlice.reducer
\ No newline at end of file
diff --git a/frontend/src/features/cypher/CypherUtil.js b/frontend/src/features/cypher/CypherUtil.js
new file mode 100644
index 0000000..8cee0a1
--- /dev/null
+++ b/frontend/src/features/cypher/CypherUtil.js
@@ -0,0 +1,285 @@
+
+
+
+export const labelColors = [
+    { color: '#604A0E', borderColor: '#423204', fontColor: '#FFF', labels: new Set([]), index: 0 },
+    { color: '#C990C0', borderColor: '#B261A5', fontColor: '#FFF', labels: new Set([]), index: 1 },
+    { color: '#F79767', borderColor: '#F36924', fontColor: '#FFF', labels: new Set([]), index: 2 },
+    { color: '#57C7E3', borderColor: '#23B3D7', fontColor: '#2A2C34', labels: new Set([]), index: 3 },
+    { color: '#F16667', borderColor: '#EB2728', fontColor: '#FFF', labels: new Set([]), index: 4 },
+    { color: '#D9C8AE', borderColor: '#C0A378', fontColor: '#2A2C34', labels: new Set([]), index: 5 },
+    { color: '#8DCC93', borderColor: '#5DB665', fontColor: '#2A2C34', labels: new Set([]), index: 6 },
+    { color: '#ECB5C9', borderColor: '#DA7298', fontColor: '#2A2C34', labels: new Set([]), index: 7 },
+    { color: '#498EDA', borderColor: '#2870C2', fontColor: '#FFF', labels: new Set([]), index: 8 },
+    { color: '#FFC454', borderColor: '#D7A013', fontColor: '#2A2C34', labels: new Set([]), index: 9 },
+    { color: '#DA7194', borderColor: '#CC3C6C', fontColor: '#FFF', labels: new Set([]), index: 10 },
+    { color: '#569480', borderColor: '#447666', fontColor: '#FFF', labels: new Set([]), index: 11 }
+]
+
+export const nodeLabelSizes = [
+    { size: 11, labels: new Set([]), index: 0 },
+    { size: 33, labels: new Set([]), index: 0 },
+    { size: 55, labels: new Set([]), index: 0 },
+    { size: 77, labels: new Set([]), index: 0 },
+    { size: 99, labels: new Set([]), index: 0 }
+]
+
+
+export const edgeLabelSizes = [
+    { size: 1, labels: new Set([]), index: 0 },
+    { size: 6, labels: new Set([]), index: 0 },
+    { size: 11, labels: new Set([]), index: 0 },
+    { size: 16, labels: new Set([]), index: 0 },
+    { size: 21, labels: new Set([]), index: 0 }
+]
+
+export let nodelabelCaptions = {}
+export let edgelabelCaptions = {}
+
+
+const getCaption = (valType, val) => {
+    if (valType === 'node' && nodelabelCaptions.hasOwnProperty(val.label)) {
+        return nodelabelCaptions[val.label]
+    } else if (valType === 'edge' && nodelabelCaptions.hasOwnProperty(val.label)) {
+        return edgelabelCaptions[val.label]
+        
+    }
+
+    let caption = valType === 'node' ? 'gid' : 'label'
+    const properties = val.properties
+    if (properties !== undefined) {
+        if (properties.hasOwnProperty('name')) {caption = 'name'}
+        else if (properties.hasOwnProperty('id')) {caption = 'id'}
+    } 
+
+    return caption
+}
+
+const getColor = (labelName) => {
+    let selectedColor = {}
+    labelColors.forEach((labelColor) => {
+        if (labelColor.labels.has(labelName)) {
+            selectedColor = { color: labelColor.color, borderColor : labelColor.borderColor, fontColor : labelColor.fontColor}
+        }
+    })
+
+    if (Object.keys(selectedColor).length === 0) {
+        const randomIndex = Math.floor(Math.random() * (11 - 0 + 1)) + 0
+        labelColors[randomIndex].labels.add(labelName)
+        selectedColor = { color: labelColors[randomIndex].color, borderColor : labelColors[randomIndex].borderColor, fontColor : labelColors[randomIndex].fontColor}
+    }
+    return selectedColor
+}
+
+const getNodeSize = (labelName) => {
+    let selectedSize = 0
+
+    nodeLabelSizes.forEach((labelSize) => {
+        if (labelSize.labels.has(labelName)) {
+            selectedSize = labelSize.size
+        }
+    })
+    
+    if (selectedSize === 0 ) {
+        nodeLabelSizes[2].labels.add(labelName)
+        selectedSize = nodeLabelSizes[2].size
+    }   
+
+    return selectedSize
+}
+
+const getEdgeSize = (labelName) => {
+    let selectedSize = 0
+
+    edgeLabelSizes.forEach((labelSize) => {
+        if (labelSize.labels.has(labelName)) {
+            selectedSize = labelSize.size
+        }
+    })
+    
+    if (selectedSize === 0 ) {
+        edgeLabelSizes[0].labels.add(labelName)
+        selectedSize = edgeLabelSizes[0].size
+    }   
+
+    return selectedSize
+}
+
+const sortByKey = (data) => {    
+    const sorted = {};
+    if (data === undefined) {
+        return sorted
+    }
+    Object.keys(data).sort().forEach(function(key) {
+        sorted[key] = data[key];
+    });
+    return sorted;
+}
+
+export const updateLabelColor = (labelName, newLabelColor) => {
+    labelColors.forEach((labelColor) => {
+        if (labelColor.labels.has(labelName)) {
+            labelColor.labels.delete(labelName)
+        }
+
+        if (labelColor.color === newLabelColor.color) {
+            labelColor.labels.add(labelName)            
+        }
+    })
+}
+
+export const updateNodeLabelSize = (labelName, newLabelSize) => {
+    nodeLabelSizes.forEach((labelSize) => {
+        if (labelSize.labels.has(labelName)) {
+            labelSize.labels.delete(labelName)
+        }
+
+        if (labelSize.size === newLabelSize) {
+            labelSize.labels.add(labelName)            
+        }
+    })
+}
+
+
+export const updateEdgeLabelSize = (labelName, newLabelSize) => {
+    edgeLabelSizes.forEach((labelSize) => {
+        if (labelSize.labels.has(labelName)) {
+            labelSize.labels.delete(labelName)
+        }
+
+        if (labelSize.size === newLabelSize) {
+            labelSize.labels.add(labelName)            
+        }
+    })
+}
+
+
+export const updateLabelCaption = (labelType, labelName, newLabelCaption) => {
+    if (labelType === 'node') {
+        nodelabelCaptions[labelName] = newLabelCaption
+    } else {
+        edgelabelCaptions[labelName] = newLabelCaption
+    }
+}
+
+export const reGenerateCytoscapeElements = (data, labels) => {
+    let nodes = []
+    let edges = []
+    let nodeLegend = {}
+    let edgeLegend = {}
+
+    if (data) {
+        data['rows'].forEach((row, index) => {
+            for (const [alias, val] of Object.entries(row)) {
+                let labelName = val['label']
+                if (val['start'] && val['end']) {
+                    if (!edgeLegend.hasOwnProperty(labelName)) { edgeLegend[labelName] = { color: '#8C8C8C', borderColor : '#8C8C8C', fontColor:'#2A2C34', size: getEdgeSize(labelName), caption: getCaption('edge', val)  } }
+                    if (!edgelabelCaptions.hasOwnProperty(labelName)) {edgelabelCaptions[labelName] = 'label'}
+                    edges.push(
+                        {
+                            group: 'edges'
+                            , data: {
+                                id: val.id
+                                , source: val.start
+                                , target: val.end
+                                , label: val.label
+                                , backgroundColor: edgeLegend[labelName].color
+                                , borderColor: edgeLegend[labelName].borderColor
+                                , fontColor: edgeLegend[labelName].fontColor
+                                , size: edgeLegend[labelName].size
+                                , properties: val.properties
+                                , caption: edgeLegend[labelName].caption
+                            }
+                            , alias: alias
+                            , classes: ['node']
+                        }
+                    )
+                } else {
+                    if (!nodeLegend.hasOwnProperty(labelName)) { nodeLegend[labelName] = Object.assign({size: getNodeSize(labelName), caption: getCaption('node', val)}, getColor(labelName)) } 
+                    if (!nodelabelCaptions.hasOwnProperty(labelName)) {nodelabelCaptions[labelName] = 'gid'}
+                    nodes.push(
+                        {
+                            group: 'nodes'
+                            , data: {
+                                id: val.id
+                                , label: val.label
+                                , backgroundColor: nodeLegend[labelName].color
+                                , borderColor: nodeLegend[labelName].borderColor
+                                , fontColor: nodeLegend[labelName].fontColor
+                                , size: nodeLegend[labelName].size
+                                , properties: val.properties
+                                , caption: nodeLegend[labelName].caption
+                            }
+                            , alias: alias
+                            , classes: ['node']
+                        }
+                    )
+                }
+            }
+        });
+    }
+  
+    return { legend: { nodeLegend: sortByKey(nodeLegend), edgeLegend: sortByKey(edgeLegend) }, elements: { nodes: nodes, edges: edges } }
+}
+
+export const generateCytoscapeElement = (data) => {
+    let nodes = []
+    let edges = []
+    let nodeLegend = {}
+    let edgeLegend = {}
+    console.log("data>> " , data)
+
+    if (data) {
+        data['rows'].forEach((row, index) => {
+            for (const [alias, val] of Object.entries(row)) {
+                let labelName = val['label']
+                if (val['start'] && val['end']) {
+                    if (!edgeLegend.hasOwnProperty(labelName)) { edgeLegend[labelName] = { color: '#8C8C8C', borderColor : '#8C8C8C', fontColor:'#2A2C34', size: getEdgeSize(labelName), caption: getCaption('edge', val) } }
+                    if (!edgelabelCaptions.hasOwnProperty(labelName)) {edgelabelCaptions[labelName] = 'label'}
+                    edges.push(
+                        {
+                            group: 'edges'
+                            , data: {
+                                id: val.id
+                                , source: val.start
+                                , target: val.end
+                                , label: val.label
+                                , backgroundColor: edgeLegend[labelName].color
+                                , borderColor: edgeLegend[labelName].borderColor
+                                , fontColor: edgeLegend[labelName].fontColor
+                                , size: edgeLegend[labelName].size
+                                , properties: val.properties
+                                , caption: edgeLegend[labelName].caption
+                            }
+                            , alias: alias
+                            , classes: ['node']
+                        }
+                    )
+                } else {
+                    if (!nodeLegend.hasOwnProperty(labelName)) { nodeLegend[labelName] = Object.assign({size: getNodeSize(labelName), caption: getCaption('node', val)}, getColor(labelName)) } 
+                    if (!nodelabelCaptions.hasOwnProperty(labelName)) {nodelabelCaptions[labelName] = 'gid'}
+                    nodes.push(
+                        {
+                            group: 'nodes'
+                            , data: {
+                                id: val.id
+                                , label: val.label
+                                , backgroundColor: nodeLegend[labelName].color
+                                , borderColor: nodeLegend[labelName].borderColor
+                                , fontColor: nodeLegend[labelName].fontColor
+                                , size: nodeLegend[labelName].size
+                                , properties: val.properties
+                                , caption: nodeLegend[labelName].caption
+                            }
+                            , alias: alias
+                            , classes: ['node']
+                        }
+                    )
+                }
+            }
+        });
+    }
+  
+    return { legend: { nodeLegend: sortByKey(nodeLegend), edgeLegend: sortByKey(edgeLegend) }, elements: { nodes: nodes, edges: edges } }
+
+}
\ No newline at end of file
diff --git a/frontend/src/features/database/DatabaseSlice.js b/frontend/src/features/database/DatabaseSlice.js
index a401ab3..38164cf 100644
--- a/frontend/src/features/database/DatabaseSlice.js
+++ b/frontend/src/features/database/DatabaseSlice.js
@@ -3,58 +3,87 @@
 export const connectToAgensGraph = createAsyncThunk(
   'database/connectToAgensGraph',
   async (formData) => {
-    const response = await fetch('/api/v1/db/connect', 
-    {method: 'POST',
-      headers: {
+    const response = await fetch('/api/v1/db/connect',
+      {
+        method: 'POST',
+        headers: {
           Accept: 'application/json',
           'Content-Type': 'application/json',
-      },
-      body: JSON.stringify(formData)
-    })
-    const res = await response.json();
-    return res.data
+        },
+        body: JSON.stringify(formData)
+      })
+    return await response.json();
   }
 )
 
 export const disconnectToAgensGraph = createAsyncThunk(
   'database/disconnectToAgensGraph',
   async () => {
-    const response = await fetch('/api/v1/db/disconnect')
-    return response.data
+    return await fetch('/api/v1/db/disconnect')
+  }
+)
+
+export const getConnectionStatus = createAsyncThunk(
+  'database/getConnectionStatus',
+  async () => {
+    const response = await fetch('/api/v1/db')
+    return await response.json();
   }
 )
 
 const DatabaseSlice = createSlice({
   name: 'database',
   initialState: {
-    host: '',
-    port: '',
-    user: '',
-    password: '',
-    database: '',
-    graph: '',
-    status: 'disconnected'
+    status: 'init'
   },
   reducers: {
   },
   extraReducers: {
     [connectToAgensGraph.fulfilled]: (state, action) => {
-      state.host = action.payload.host !== '' ? action.payload.host : state.host
-      state.port = action.payload.port !== '' ? action.payload.port : state.port
-      state.user = action.payload.user !== '' ? action.payload.user : state.user
-      state.password = action.payload.password !== '' ? action.payload.password : state.password
-      state.database = action.payload.database !== '' ? action.payload.database : state.database
-      state.graph = action.payload.graph !== '' ? action.payload.graph : state.graph
-      state.status = 'connected'
-    },     
+      return {
+        host: action.payload.host
+        , port: action.payload.port
+        , user: action.payload.user
+        , password: action.payload.password
+        , database: action.payload.database
+        , graph: action.payload.graph
+        , status: 'connected'
+      }
+    },
     [disconnectToAgensGraph.fulfilled]: (state, action) => {
-      state.host = ''
-      state.port = ''
-      state.user = ''
-      state.password = ''
-      state.database = ''
-      state.graph = ''
-      state.status = 'disconnected'
+      return {
+        host: ''
+        , port: ''
+        , user: ''
+        , password: ''
+        , database: ''
+        , graph: ''
+        , status: 'disconnected'
+      }
+    },
+    [getConnectionStatus.fulfilled]: (state, action) => {
+      if (action.payload) {
+        return {
+          host: action.payload.host
+          , port: action.payload.port
+          , user: action.payload.user
+          , password: action.payload.password
+          , database: action.payload.database
+          , graph: action.payload.graph
+          , status: 'connected'
+        }
+      } else {
+        return {
+          host: ''
+          , port: ''
+          , user: ''
+          , password: ''
+          , database: ''
+          , graph: ''
+          , status: 'disconnected'
+        }
+      }
+
     }
   }
 })
diff --git a/frontend/src/features/database/MetadataSlice.js b/frontend/src/features/database/MetadataSlice.js
new file mode 100644
index 0000000..3ce1970
--- /dev/null
+++ b/frontend/src/features/database/MetadataSlice.js
@@ -0,0 +1,38 @@
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
+
+export const getMetaData = createAsyncThunk(
+  'database/getMetaData',
+  async () => {
+    const response = await fetch('/api/v1/db/meta')
+    const res = await response.json();
+    return res
+  }
+)
+
+const MetadataSlice = createSlice({
+  name: 'metadata',
+  initialState: {
+    status: 'init'
+  },
+  reducers: {
+  },
+  extraReducers: {
+    [getMetaData.fulfilled]: (state, action) => {
+      if (action.payload) {
+        return {
+          edges: action.payload.edges,
+          nodes: action.payload.nodes,
+          propertyKeys: action.payload.propertyKeys
+        }
+      } else {
+        return {
+          edges: [],
+          nodes: [],
+          propertyKeys: []
+        }
+      }
+    }
+  }
+})
+
+export default MetadataSlice.reducer
\ No newline at end of file
diff --git a/frontend/src/features/frame/FrameSlice.js b/frontend/src/features/frame/FrameSlice.js
index 4c44a06..b8187f3 100644
--- a/frontend/src/features/frame/FrameSlice.js
+++ b/frontend/src/features/frame/FrameSlice.js
@@ -3,27 +3,28 @@
 
 const FrameSlice = createSlice({
   name: 'frames',
-  initialState: [{ frameName: 'ServerConnect', frameProps: { key: uuid(), reqString: ':server connect' } }],
+  initialState: [],
   reducers: {
     addFrame: {
       reducer: (state, action) => {
         const reqString = action.payload.reqString.trim().toLowerCase()
-
+        let refKey = action.payload.refKey ? action.payload.refKey : uuid()
         if (reqString === ':server status') {
-          state.unshift({ frameName: 'ServerStatus', frameProps: { key: uuid(), reqString: reqString } })
+          state.unshift({ frameName: 'ServerStatus', frameProps: { key: refKey, reqString: reqString } })
         } else if (reqString === ':server connect') {
-          state.unshift({ frameName: 'ServerConnect', frameProps: { key: uuid(), reqString: reqString } })
+          state.unshift({ frameName: 'ServerConnect', frameProps: { key: refKey, reqString: reqString } })
         } else if (reqString === ':server disconnect') {
-          state.unshift({ frameName: 'ServerDisconnect', frameProps: { key: uuid(), reqString: reqString } })
-        } else if (reqString.startsWith('match')) {
-          state.unshift({ frameName: 'CypherResultFrame', frameProps: { key: uuid(), reqString: reqString } })
+          state.unshift({ frameName: 'ServerDisconnect', frameProps: { key: refKey, reqString: reqString } })
+        } else if (reqString.match("(match|create).*")) {
+          state.unshift({ frameName: 'CypherResultFrame', frameProps: { key: refKey, reqString: reqString } })
         } else {
           alert("Can't understand your command")
           return;
         }
       },
-      prepare: (reqString) => {
-        return { payload: { reqString } }
+      prepare: (reqString, refKey) => {
+        console.log("reqString, refKey >> ", reqString, refKey)
+        return { payload: { reqString, refKey } }
       }
     },
     removeFrame: {
diff --git a/frontend/src/features/menu/MenuSlice.js b/frontend/src/features/menu/MenuSlice.js
index b42614c..10b52da 100644
--- a/frontend/src/features/menu/MenuSlice.js
+++ b/frontend/src/features/menu/MenuSlice.js
@@ -4,18 +4,22 @@
   name: 'navigator',
   initialState: {
     menuList: [['home', 'home'], ['setting', 'cog']],
-    activeMenu: ''
+    activeMenu: 'init',
+    isActive: false
   },
   reducers: {
     toggleMenu: {
       reducer: (state, action) => {
+        let isActive = true
         if (state.activeMenu === action.payload.selectedMenuName) {
           action.payload.selectedMenuName = ''
+          isActive = false
         }
         state.activeMenu = action.payload.selectedMenuName
+        state.isActive = isActive
       },
-      prepare: (activeMenuName, selectedMenuName) => {
-        return { payload : {activeMenuName, selectedMenuName}}
+      prepare: (selectedMenuName) => {
+        return { payload : {selectedMenuName}}
       }
     }
   }
diff --git a/package.json b/package.json
index a1337b6..dc4b940 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,13 @@
     "version": "0.0.1",
     "private": true,
     "scripts": {
-        "setup-main": "npm install",
+        "setup": "npm install && npm-run-all setup-front setup-backend",
         "setup-front": "cd frontend && npm install",
         "setup-backend": "cd backend && npm install",
-        "setup": "npm-run-all --parallel setup-main setup-front setup-backend",
         "front": "cd frontend && npm run start",
+        "build-front": "cd frontend && yarn build",
         "backend": "cd backend && npm run start",
+        "deploy": "npm-run-all build-front backend",
         "start": "npm-run-all --parallel backend front"
     },
     "dependencies": {