diff --git a/.nyc_output/126e95e1-65f4-48bc-83ee-8648e86bd69e.json b/.nyc_output/126e95e1-65f4-48bc-83ee-8648e86bd69e.json
new file mode 100644
index 0000000000000000000000000000000000000000..9e26dfeeb6e641a33dae4961196235bdb965b21b
--- /dev/null
+++ b/.nyc_output/126e95e1-65f4-48bc-83ee-8648e86bd69e.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/index.html b/index.html
index abf2e772c44d380abbd4f691e7f3de3b055aa47c..a1005ed5b08df15b777afb69116eaa15589c087a 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
-    <title>jabar-viz-masy</title>
+    <title>APBD Elektronik Provinsi Jawa Barat</title>
   </head>
   <body>
     <div id="app"></div>
diff --git a/package-lock.json b/package-lock.json
index 1713a45e058338e480662dd5179faa909ef85992..da35d07e4b05a2bef59b5901a8f9fd84961ac744 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,22 @@
         "node-fetch": "^2.3.0"
       }
     },
+    "@vue/test-utils": {
+      "version": "1.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-1.0.0-beta.29.tgz",
+      "integrity": "sha512-yX4sxEIHh4M9yAbLA/ikpEnGKMNBCnoX98xE1RwxfhQVcn0MaXNSj1Qmac+ZydTj6VBSEVukchBogXBTwc+9iA==",
+      "dev": true,
+      "requires": {
+        "dom-event-types": "^1.0.0",
+        "lodash": "^4.17.4"
+      }
+    },
+    "abab": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
+      "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==",
+      "dev": true
+    },
     "abbrev": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -53,6 +69,30 @@
         }
       }
     },
+    "acorn-globals": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz",
+      "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==",
+      "dev": true,
+      "requires": {
+        "acorn": "^6.0.1",
+        "acorn-walk": "^6.0.1"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "6.1.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
+          "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
+          "dev": true
+        }
+      }
+    },
+    "acorn-walk": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
+      "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==",
+      "dev": true
+    },
     "ajv": {
       "version": "5.5.2",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
@@ -94,6 +134,12 @@
       "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
       "dev": true
     },
+    "ansi-colors": {
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
+      "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
+      "dev": true
+    },
     "ansi-html": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
@@ -178,6 +224,12 @@
       "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
       "dev": true
     },
+    "array-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
+      "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
+      "dev": true
+    },
     "array-find-index": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@@ -1416,6 +1468,18 @@
       "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
       "dev": true
     },
+    "browser-process-hrtime": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
+      "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==",
+      "dev": true
+    },
+    "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
+    },
     "browserify-aes": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
@@ -1936,8 +2000,7 @@
     "commander": {
       "version": "2.17.1",
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
-      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
-      "dev": true
+      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
     },
     "commondir": {
       "version": "1.0.1",
@@ -2494,6 +2557,21 @@
         }
       }
     },
+    "cssom": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz",
+      "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==",
+      "dev": true
+    },
+    "cssstyle": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz",
+      "integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==",
+      "dev": true,
+      "requires": {
+        "cssom": "0.3.x"
+      }
+    },
     "cuint": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
@@ -2524,6 +2602,270 @@
         "es5-ext": "^0.10.9"
       }
     },
+    "d3": {
+      "version": "5.9.2",
+      "resolved": "https://registry.npmjs.org/d3/-/d3-5.9.2.tgz",
+      "integrity": "sha512-ydrPot6Lm3nTWH+gJ/Cxf3FcwuvesYQ5uk+j/kXEH/xbuYWYWTMAHTJQkyeuG8Y5WM5RSEYB41EctUrXQQytRQ==",
+      "requires": {
+        "d3-array": "1",
+        "d3-axis": "1",
+        "d3-brush": "1",
+        "d3-chord": "1",
+        "d3-collection": "1",
+        "d3-color": "1",
+        "d3-contour": "1",
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-dsv": "1",
+        "d3-ease": "1",
+        "d3-fetch": "1",
+        "d3-force": "1",
+        "d3-format": "1",
+        "d3-geo": "1",
+        "d3-hierarchy": "1",
+        "d3-interpolate": "1",
+        "d3-path": "1",
+        "d3-polygon": "1",
+        "d3-quadtree": "1",
+        "d3-random": "1",
+        "d3-scale": "2",
+        "d3-scale-chromatic": "1",
+        "d3-selection": "1",
+        "d3-shape": "1",
+        "d3-time": "1",
+        "d3-time-format": "2",
+        "d3-timer": "1",
+        "d3-transition": "1",
+        "d3-voronoi": "1",
+        "d3-zoom": "1"
+      }
+    },
+    "d3-array": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+      "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+    },
+    "d3-axis": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz",
+      "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
+    },
+    "d3-brush": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.6.tgz",
+      "integrity": "sha512-lGSiF5SoSqO5/mYGD5FAeGKKS62JdA1EV7HPrU2b5rTX4qEJJtpjaGLJngjnkewQy7UnGstnFd3168wpf5z76w==",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "1",
+        "d3-transition": "1"
+      }
+    },
+    "d3-chord": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz",
+      "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==",
+      "requires": {
+        "d3-array": "1",
+        "d3-path": "1"
+      }
+    },
+    "d3-collection": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
+      "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
+    },
+    "d3-color": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.2.3.tgz",
+      "integrity": "sha512-x37qq3ChOTLd26hnps36lexMRhNXEtVxZ4B25rL0DVdDsGQIJGB18S7y9XDwlDD6MD/ZBzITCf4JjGMM10TZkw=="
+    },
+    "d3-contour": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz",
+      "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==",
+      "requires": {
+        "d3-array": "^1.1.1"
+      }
+    },
+    "d3-dispatch": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.5.tgz",
+      "integrity": "sha512-vwKx+lAqB1UuCeklr6Jh1bvC4SZgbSqbkGBLClItFBIYH4vqDJCA7qfoy14lXmJdnBOdxndAMxjCbImJYW7e6g=="
+    },
+    "d3-drag": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.3.tgz",
+      "integrity": "sha512-8S3HWCAg+ilzjJsNtWW1Mutl74Nmzhb9yU6igspilaJzeZVFktmY6oO9xOh5TDk+BM2KrNFjttZNoJJmDnkjkg==",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-selection": "1"
+      }
+    },
+    "d3-dsv": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.1.1.tgz",
+      "integrity": "sha512-1EH1oRGSkeDUlDRbhsFytAXU6cAmXFzc52YUe6MRlPClmWb85MP1J5x+YJRzya4ynZWnbELdSAvATFW/MbxaXw==",
+      "requires": {
+        "commander": "2",
+        "iconv-lite": "0.4",
+        "rw": "1"
+      }
+    },
+    "d3-ease": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.5.tgz",
+      "integrity": "sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ=="
+    },
+    "d3-fetch": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.2.tgz",
+      "integrity": "sha512-S2loaQCV/ZeyTyIF2oP8D1K9Z4QizUzW7cWeAOAS4U88qOt3Ucf6GsmgthuYSdyB2HyEm4CeGvkQxWsmInsIVA==",
+      "requires": {
+        "d3-dsv": "1"
+      }
+    },
+    "d3-force": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz",
+      "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==",
+      "requires": {
+        "d3-collection": "1",
+        "d3-dispatch": "1",
+        "d3-quadtree": "1",
+        "d3-timer": "1"
+      }
+    },
+    "d3-format": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.3.2.tgz",
+      "integrity": "sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ=="
+    },
+    "d3-geo": {
+      "version": "1.11.3",
+      "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.11.3.tgz",
+      "integrity": "sha512-n30yN9qSKREvV2fxcrhmHUdXP9TNH7ZZj3C/qnaoU0cVf/Ea85+yT7HY7i8ySPwkwjCNYtmKqQFTvLFngfkItQ==",
+      "requires": {
+        "d3-array": "1"
+      }
+    },
+    "d3-hierarchy": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz",
+      "integrity": "sha512-L+GHMSZNwTpiq4rt9GEsNcpLa4M96lXMR8M/nMG9p5hBE0jy6C+3hWtyZMenPQdwla249iJy7Nx0uKt3n+u9+w=="
+    },
+    "d3-interpolate": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.3.2.tgz",
+      "integrity": "sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w==",
+      "requires": {
+        "d3-color": "1"
+      }
+    },
+    "d3-path": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.7.tgz",
+      "integrity": "sha512-q0cW1RpvA5c5ma2rch62mX8AYaiLX0+bdaSM2wxSU9tXjU4DNvkx9qiUvjkuWCj3p22UO/hlPivujqMiR9PDzA=="
+    },
+    "d3-polygon": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.5.tgz",
+      "integrity": "sha512-RHhh1ZUJZfhgoqzWWuRhzQJvO7LavchhitSTHGu9oj6uuLFzYZVeBzaWTQ2qSO6bz2w55RMoOCf0MsLCDB6e0w=="
+    },
+    "d3-quadtree": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.6.tgz",
+      "integrity": "sha512-NUgeo9G+ENQCQ1LsRr2qJg3MQ4DJvxcDNCiohdJGHt5gRhBW6orIB5m5FJ9kK3HNL8g9F4ERVoBzcEwQBfXWVA=="
+    },
+    "d3-random": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz",
+      "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ=="
+    },
+    "d3-scale": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz",
+      "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==",
+      "requires": {
+        "d3-array": "^1.2.0",
+        "d3-collection": "1",
+        "d3-format": "1",
+        "d3-interpolate": "1",
+        "d3-time": "1",
+        "d3-time-format": "2"
+      }
+    },
+    "d3-scale-chromatic": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.3.3.tgz",
+      "integrity": "sha512-BWTipif1CimXcYfT02LKjAyItX5gKiwxuPRgr4xM58JwlLocWbjPLI7aMEjkcoOQXMkYsmNsvv3d2yl/OKuHHw==",
+      "requires": {
+        "d3-color": "1",
+        "d3-interpolate": "1"
+      }
+    },
+    "d3-selection": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.0.tgz",
+      "integrity": "sha512-EYVwBxQGEjLCKF2pJ4+yrErskDnz5v403qvAid96cNdCMr8rmCYfY5RGzWz24mdIbxmDf6/4EAH+K9xperD5jg=="
+    },
+    "d3-shape": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.5.tgz",
+      "integrity": "sha512-VKazVR3phgD+MUCldapHD7P9kcrvPcexeX/PkMJmkUov4JM8IxsSg1DvbYoYich9AtdTsa5nNk2++ImPiDiSxg==",
+      "requires": {
+        "d3-path": "1"
+      }
+    },
+    "d3-time": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.11.tgz",
+      "integrity": "sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw=="
+    },
+    "d3-time-format": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.3.tgz",
+      "integrity": "sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA==",
+      "requires": {
+        "d3-time": "1"
+      }
+    },
+    "d3-timer": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.9.tgz",
+      "integrity": "sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg=="
+    },
+    "d3-transition": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.2.0.tgz",
+      "integrity": "sha512-VJ7cmX/FPIPJYuaL2r1o1EMHLttvoIuZhhuAlRoOxDzogV8iQS6jYulDm3xEU3TqL80IZIhI551/ebmCMrkvhw==",
+      "requires": {
+        "d3-color": "1",
+        "d3-dispatch": "1",
+        "d3-ease": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "^1.1.0",
+        "d3-timer": "1"
+      }
+    },
+    "d3-voronoi": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz",
+      "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg=="
+    },
+    "d3-zoom": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.3.tgz",
+      "integrity": "sha512-xEBSwFx5Z9T3/VrwDkMt+mr0HCzv7XjpGURJ8lWmIC8wxe32L39eWHIasEe/e7Ox8MPU4p1hvH8PKN2olLzIBg==",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "1",
+        "d3-transition": "1"
+      }
+    },
     "dashdash": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -2533,6 +2875,17 @@
         "assert-plus": "^1.0.0"
       }
     },
+    "data-urls": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
+      "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
+      "dev": true,
+      "requires": {
+        "abab": "^2.0.0",
+        "whatwg-mimetype": "^2.2.0",
+        "whatwg-url": "^7.0.0"
+      }
+    },
     "date-now": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
@@ -2572,6 +2925,12 @@
       "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
       "dev": true
     },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
     "define-properties": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -2705,6 +3064,12 @@
       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
       "dev": true
     },
+    "detect-file": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+      "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+      "dev": true
+    },
     "detect-indent": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
@@ -2720,6 +3085,12 @@
       "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
       "dev": true
     },
+    "diff": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+      "dev": true
+    },
     "diffie-hellman": {
       "version": "5.0.3",
       "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@@ -2774,6 +3145,12 @@
         "utila": "~0.4"
       }
     },
+    "dom-event-types": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/dom-event-types/-/dom-event-types-1.0.0.tgz",
+      "integrity": "sha512-2G2Vwi2zXTHBGqXHsJ4+ak/iP0N8Ar+G8a7LiD2oup5o4sQWytwqqrZu/O6hIMV0KMID2PL69OhpshLO0n7UJQ==",
+      "dev": true
+    },
     "dom-serializer": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
@@ -2796,6 +3173,15 @@
       "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
       "dev": true
     },
+    "domexception": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
+      "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
+      "dev": true,
+      "requires": {
+        "webidl-conversions": "^4.0.2"
+      }
+    },
     "domhandler": {
       "version": "2.4.2",
       "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
@@ -3049,6 +3435,27 @@
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
+    "escodegen": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz",
+      "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==",
+      "dev": true,
+      "requires": {
+        "esprima": "^3.1.3",
+        "estraverse": "^4.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1",
+        "source-map": "~0.6.1"
+      },
+      "dependencies": {
+        "esprima": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+          "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
+          "dev": true
+        }
+      }
+    },
     "escope": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
@@ -3227,6 +3634,15 @@
         }
       }
     },
+    "expand-tilde": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
     "express": {
       "version": "4.16.4",
       "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz",
@@ -3393,6 +3809,12 @@
       "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
       "dev": true
     },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
     "fastparse": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
@@ -3524,6 +3946,46 @@
         "locate-path": "^2.0.0"
       }
     },
+    "findup-sync": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+      "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+      "dev": true,
+      "requires": {
+        "detect-file": "^1.0.0",
+        "is-glob": "^3.1.0",
+        "micromatch": "^3.0.4",
+        "resolve-dir": "^1.0.1"
+      },
+      "dependencies": {
+        "is-glob": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^2.1.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"
+      },
+      "dependencies": {
+        "is-buffer": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz",
+          "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==",
+          "dev": true
+        }
+      }
+    },
     "flatten": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
@@ -3705,7 +4167,8 @@
         "ansi-regex": {
           "version": "2.1.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -3726,12 +4189,14 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -3746,17 +4211,20 @@
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -3873,7 +4341,8 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "ini": {
           "version": "1.3.5",
@@ -3885,6 +4354,7 @@
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -3899,6 +4369,7 @@
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -3906,12 +4377,14 @@
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "minipass": {
           "version": "2.3.5",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
@@ -3930,6 +4403,7 @@
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -4010,7 +4484,8 @@
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -4022,6 +4497,7 @@
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -4107,7 +4583,8 @@
         "safe-buffer": {
           "version": "5.1.2",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -4143,6 +4620,7 @@
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -4162,6 +4640,7 @@
           "version": "3.0.1",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -4205,12 +4684,14 @@
         "wrappy": {
           "version": "1.0.2",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "yallist": {
           "version": "3.0.3",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         }
       }
     },
@@ -4383,6 +4864,30 @@
         }
       }
     },
+    "global-modules": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+      "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+      "dev": true,
+      "requires": {
+        "global-prefix": "^1.0.1",
+        "is-windows": "^1.0.1",
+        "resolve-dir": "^1.0.0"
+      }
+    },
+    "global-prefix": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+      "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "homedir-polyfill": "^1.0.1",
+        "ini": "^1.3.4",
+        "is-windows": "^1.0.1",
+        "which": "^1.2.14"
+      }
+    },
     "globals": {
       "version": "9.18.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
@@ -4420,6 +4925,12 @@
       "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
       "dev": true
     },
+    "growl": {
+      "version": "1.10.5",
+      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+      "dev": true
+    },
     "growly": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
@@ -4604,6 +5115,15 @@
         "os-tmpdir": "^1.0.1"
       }
     },
+    "homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "requires": {
+        "parse-passwd": "^1.0.0"
+      }
+    },
     "hosted-git-info": {
       "version": "2.7.1",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
@@ -4628,9 +5148,18 @@
       "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
       "dev": true
     },
-    "html-entities": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
+    "html-encoding-sniffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
+      "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+      "dev": true,
+      "requires": {
+        "whatwg-encoding": "^1.0.1"
+      }
+    },
+    "html-entities": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
       "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=",
       "dev": true
     },
@@ -4888,7 +5417,6 @@
       "version": "0.4.23",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
       "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
-      "dev": true,
       "requires": {
         "safer-buffer": ">= 2.1.2 < 3"
       }
@@ -5003,6 +5531,12 @@
       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
       "dev": true
     },
+    "ini": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+      "dev": true
+    },
     "internal-ip": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz",
@@ -5347,6 +5881,73 @@
       "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
       "dev": true
     },
+    "jsdom": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.0.0.tgz",
+      "integrity": "sha512-/VkyPmdtbwqpJSkwDx3YyJ3U1oawYNB/h5z8vTUZGAzjtu2OHTeFRfnJqyMHsJ5Cyes23trOmvUpM1GfHH1leA==",
+      "dev": true,
+      "requires": {
+        "abab": "^2.0.0",
+        "acorn": "^6.0.4",
+        "acorn-globals": "^4.3.0",
+        "array-equal": "^1.0.0",
+        "cssom": "^0.3.4",
+        "cssstyle": "^1.1.1",
+        "data-urls": "^1.1.0",
+        "domexception": "^1.0.1",
+        "escodegen": "^1.11.0",
+        "html-encoding-sniffer": "^1.0.2",
+        "nwsapi": "^2.0.9",
+        "parse5": "5.1.0",
+        "pn": "^1.1.0",
+        "request": "^2.88.0",
+        "request-promise-native": "^1.0.5",
+        "saxes": "^3.1.5",
+        "symbol-tree": "^3.2.2",
+        "tough-cookie": "^2.5.0",
+        "w3c-hr-time": "^1.0.1",
+        "w3c-xmlserializer": "^1.0.1",
+        "webidl-conversions": "^4.0.2",
+        "whatwg-encoding": "^1.0.5",
+        "whatwg-mimetype": "^2.3.0",
+        "whatwg-url": "^7.0.0",
+        "ws": "^6.1.2",
+        "xml-name-validator": "^3.0.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "6.1.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
+          "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
+          "dev": true
+        },
+        "tough-cookie": {
+          "version": "2.5.0",
+          "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+          "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+          "dev": true,
+          "requires": {
+            "psl": "^1.1.28",
+            "punycode": "^2.1.1"
+          }
+        },
+        "ws": {
+          "version": "6.2.1",
+          "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
+          "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
+          "dev": true,
+          "requires": {
+            "async-limiter": "~1.0.0"
+          }
+        }
+      }
+    },
+    "jsdom-global": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz",
+      "integrity": "sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=",
+      "dev": true
+    },
     "jsesc": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
@@ -5447,6 +6048,16 @@
         "invert-kv": "^1.0.0"
       }
     },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      }
+    },
     "load-json-file": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
@@ -5556,6 +6167,12 @@
       "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==",
       "dev": true
     },
+    "lodash.sortby": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+      "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
+      "dev": true
+    },
     "lodash.tail": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz",
@@ -5633,6 +6250,15 @@
         "pify": "^3.0.0"
       }
     },
+    "map-age-cleaner": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+      "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
+      "dev": true,
+      "requires": {
+        "p-defer": "^1.0.0"
+      }
+    },
     "map-cache": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -5987,76 +6613,765 @@
         "minimist": "0.0.8"
       }
     },
-    "move-concurrently": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
-      "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
-      "dev": true,
-      "requires": {
-        "aproba": "^1.1.1",
-        "copy-concurrently": "^1.0.0",
-        "fs-write-stream-atomic": "^1.0.8",
-        "mkdirp": "^0.5.1",
-        "rimraf": "^2.5.4",
-        "run-queue": "^1.0.3"
-      }
-    },
-    "ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-      "dev": true
-    },
-    "multicast-dns": {
-      "version": "6.2.3",
-      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
-      "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
-      "dev": true,
-      "requires": {
-        "dns-packet": "^1.3.1",
-        "thunky": "^1.0.2"
+    "mocha": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.0.2.tgz",
+      "integrity": "sha512-RtTJsmmToGyeTznSOMoM6TPEk1A84FQaHIciKrRqARZx+B5ccJ5tXlmJzEKGBxZdqk9UjpRsesZTUkZmR5YnuQ==",
+      "dev": true,
+      "requires": {
+        "ansi-colors": "3.2.3",
+        "browser-stdout": "1.3.1",
+        "debug": "3.2.6",
+        "diff": "3.5.0",
+        "escape-string-regexp": "1.0.5",
+        "findup-sync": "2.0.0",
+        "glob": "7.1.3",
+        "growl": "1.10.5",
+        "he": "1.2.0",
+        "js-yaml": "3.12.0",
+        "log-symbols": "2.2.0",
+        "minimatch": "3.0.4",
+        "mkdirp": "0.5.1",
+        "ms": "2.1.1",
+        "node-environment-flags": "1.0.4",
+        "object.assign": "4.1.0",
+        "strip-json-comments": "2.0.1",
+        "supports-color": "6.0.0",
+        "which": "1.3.1",
+        "wide-align": "1.1.3",
+        "yargs": "12.0.5",
+        "yargs-parser": "11.1.1",
+        "yargs-unparser": "1.5.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "camelcase": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz",
+          "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==",
+          "dev": true
+        },
+        "cliui": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+          "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+          "dev": true,
+          "requires": {
+            "string-width": "^2.1.1",
+            "strip-ansi": "^4.0.0",
+            "wrap-ansi": "^2.0.0"
+          }
+        },
+        "cross-spawn": {
+          "version": "6.0.5",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+          "dev": true,
+          "requires": {
+            "nice-try": "^1.0.4",
+            "path-key": "^2.0.1",
+            "semver": "^5.5.0",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
+        "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"
+          }
+        },
+        "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
+        },
+        "execa": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+          "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+          "dev": true,
+          "requires": {
+            "cross-spawn": "^6.0.0",
+            "get-stream": "^4.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"
+          }
+        },
+        "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"
+          }
+        },
+        "get-stream": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+          "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+          "dev": true,
+          "requires": {
+            "pump": "^3.0.0"
+          }
+        },
+        "invert-kv": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
+          "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "3.12.0",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+          "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
+        "lcid": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
+          "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
+          "dev": true,
+          "requires": {
+            "invert-kv": "^2.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"
+          }
+        },
+        "mem": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz",
+          "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==",
+          "dev": true,
+          "requires": {
+            "map-age-cleaner": "^0.1.1",
+            "mimic-fn": "^2.0.0",
+            "p-is-promise": "^2.0.0"
+          }
+        },
+        "mimic-fn": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz",
+          "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==",
+          "dev": true
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "dev": true
+        },
+        "os-locale": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
+          "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
+          "dev": true,
+          "requires": {
+            "execa": "^1.0.0",
+            "lcid": "^2.0.0",
+            "mem": "^4.0.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
+          "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.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"
+          }
+        },
+        "p-try": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz",
+          "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==",
+          "dev": true
+        },
+        "pump": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+          "dev": true,
+          "requires": {
+            "end-of-stream": "^1.1.0",
+            "once": "^1.3.1"
+          }
+        },
+        "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"
+          }
+        },
+        "supports-color": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
+          "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        },
+        "yargs": {
+          "version": "12.0.5",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
+          "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
+          "dev": true,
+          "requires": {
+            "cliui": "^4.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^3.0.0",
+            "get-caller-file": "^1.0.1",
+            "os-locale": "^3.0.0",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^1.0.1",
+            "set-blocking": "^2.0.0",
+            "string-width": "^2.0.0",
+            "which-module": "^2.0.0",
+            "y18n": "^3.2.1 || ^4.0.0",
+            "yargs-parser": "^11.1.1"
+          }
+        },
+        "yargs-parser": {
+          "version": "11.1.1",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
+          "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
+          "dev": true,
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
       }
     },
-    "multicast-dns-service-types": {
+    "mocha-webpack": {
       "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
-      "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
-      "dev": true
-    },
-    "nan": {
-      "version": "2.13.1",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.1.tgz",
-      "integrity": "sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==",
-      "dev": true
-    },
-    "nanomatch": {
-      "version": "1.2.13",
-      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
-      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "resolved": "https://registry.npmjs.org/mocha-webpack/-/mocha-webpack-1.1.0.tgz",
+      "integrity": "sha512-brmE0tR6G5JbEzZXspJmF/uZm2J/YM/69M3VS6ND76i6wXbebFpE+bQDaehilK8CZanNSsTCcqTTLh1PZuRKJw==",
       "dev": true,
       "requires": {
-        "arr-diff": "^4.0.0",
-        "array-unique": "^0.3.2",
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "fragment-cache": "^0.2.1",
-        "is-windows": "^1.0.2",
-        "kind-of": "^6.0.2",
-        "object.pick": "^1.3.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
+        "babel-runtime": "^6.18.0",
+        "chalk": "^2.3.0",
+        "chokidar": "^1.6.1",
+        "glob-parent": "^3.1.0",
+        "globby": "^6.1.0",
+        "interpret": "^1.0.1",
+        "is-glob": "^4.0.0",
+        "loader-utils": "^1.1.0",
+        "lodash": "^4.3.0",
+        "memory-fs": "^0.4.1",
+        "nodent-runtime": "^3.0.3",
+        "normalize-path": "^2.0.1",
+        "progress": "^2.0.0",
+        "source-map-support": "^0.5.0",
+        "strip-ansi": "^4.0.0",
+        "toposort": "^1.0.0",
+        "yargs": "^4.8.0"
       },
       "dependencies": {
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
           "dev": true
-        }
-      }
-    },
-    "negotiator": {
+        },
+        "anymatch": {
+          "version": "1.3.2",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+          "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+          "dev": true,
+          "requires": {
+            "micromatch": "^2.1.5",
+            "normalize-path": "^2.0.0"
+          }
+        },
+        "arr-diff": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+          "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.0.1"
+          }
+        },
+        "array-unique": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+          "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+          "dev": true
+        },
+        "braces": {
+          "version": "1.8.5",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+          "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+          "dev": true,
+          "requires": {
+            "expand-range": "^1.8.1",
+            "preserve": "^0.2.0",
+            "repeat-element": "^1.1.2"
+          }
+        },
+        "camelcase": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+          "dev": true
+        },
+        "chokidar": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+          "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+          "dev": true,
+          "requires": {
+            "anymatch": "^1.3.0",
+            "async-each": "^1.0.0",
+            "fsevents": "^1.0.0",
+            "glob-parent": "^2.0.0",
+            "inherits": "^2.0.1",
+            "is-binary-path": "^1.0.0",
+            "is-glob": "^2.0.0",
+            "path-is-absolute": "^1.0.0",
+            "readdirp": "^2.0.0"
+          },
+          "dependencies": {
+            "glob-parent": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+              "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+              "dev": true,
+              "requires": {
+                "is-glob": "^2.0.0"
+              }
+            },
+            "is-glob": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+              "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+              "dev": true,
+              "requires": {
+                "is-extglob": "^1.0.0"
+              }
+            }
+          }
+        },
+        "cliui": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+          "dev": true,
+          "requires": {
+            "string-width": "^1.0.1",
+            "strip-ansi": "^3.0.1",
+            "wrap-ansi": "^2.0.0"
+          },
+          "dependencies": {
+            "ansi-regex": {
+              "version": "2.1.1",
+              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+              "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+              "dev": true
+            },
+            "strip-ansi": {
+              "version": "3.0.1",
+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+              "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+              "dev": true,
+              "requires": {
+                "ansi-regex": "^2.0.0"
+              }
+            }
+          }
+        },
+        "expand-brackets": {
+          "version": "0.1.5",
+          "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+          "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+          "dev": true,
+          "requires": {
+            "is-posix-bracket": "^0.1.0"
+          }
+        },
+        "extglob": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+          "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        },
+        "find-up": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+          "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+          "dev": true,
+          "requires": {
+            "path-exists": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "globby": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+          "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+          "dev": true,
+          "requires": {
+            "array-union": "^1.0.1",
+            "glob": "^7.0.3",
+            "object-assign": "^4.0.1",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "^1.0.0"
+          }
+        },
+        "load-json-file": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+          "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "parse-json": "^2.2.0",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0",
+            "strip-bom": "^2.0.0"
+          }
+        },
+        "micromatch": {
+          "version": "2.3.11",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+          "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^2.0.0",
+            "array-unique": "^0.2.1",
+            "braces": "^1.8.2",
+            "expand-brackets": "^0.1.4",
+            "extglob": "^0.3.1",
+            "filename-regex": "^2.0.0",
+            "is-extglob": "^1.0.0",
+            "is-glob": "^2.0.1",
+            "kind-of": "^3.0.2",
+            "normalize-path": "^2.0.1",
+            "object.omit": "^2.0.0",
+            "parse-glob": "^3.0.4",
+            "regex-cache": "^0.4.2"
+          },
+          "dependencies": {
+            "is-glob": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+              "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+              "dev": true,
+              "requires": {
+                "is-extglob": "^1.0.0"
+              }
+            }
+          }
+        },
+        "normalize-path": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+          "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+          "dev": true,
+          "requires": {
+            "remove-trailing-separator": "^1.0.1"
+          }
+        },
+        "os-locale": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+          "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+          "dev": true,
+          "requires": {
+            "lcid": "^1.0.0"
+          }
+        },
+        "parse-json": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+          "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+          "dev": true,
+          "requires": {
+            "error-ex": "^1.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+          "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+          "dev": true,
+          "requires": {
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "path-type": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+          "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "pify": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "dev": true
+        },
+        "read-pkg": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+          "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+          "dev": true,
+          "requires": {
+            "load-json-file": "^1.0.0",
+            "normalize-package-data": "^2.3.2",
+            "path-type": "^1.0.0"
+          }
+        },
+        "read-pkg-up": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+          "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+          "dev": true,
+          "requires": {
+            "find-up": "^1.0.0",
+            "read-pkg": "^1.0.0"
+          }
+        },
+        "source-map-support": {
+          "version": "0.5.11",
+          "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz",
+          "integrity": "sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==",
+          "dev": true,
+          "requires": {
+            "buffer-from": "^1.0.0",
+            "source-map": "^0.6.0"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "dev": true,
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          },
+          "dependencies": {
+            "ansi-regex": {
+              "version": "2.1.1",
+              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+              "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+              "dev": true
+            },
+            "strip-ansi": {
+              "version": "3.0.1",
+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+              "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+              "dev": true,
+              "requires": {
+                "ansi-regex": "^2.0.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": "2.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+          "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+          "dev": true,
+          "requires": {
+            "is-utf8": "^0.2.0"
+          }
+        },
+        "which-module": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+          "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+          "dev": true
+        },
+        "window-size": {
+          "version": "0.2.0",
+          "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz",
+          "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=",
+          "dev": true
+        },
+        "y18n": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+          "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+          "dev": true
+        },
+        "yargs": {
+          "version": "4.8.1",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz",
+          "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=",
+          "dev": true,
+          "requires": {
+            "cliui": "^3.2.0",
+            "decamelize": "^1.1.1",
+            "get-caller-file": "^1.0.1",
+            "lodash.assign": "^4.0.3",
+            "os-locale": "^1.4.0",
+            "read-pkg-up": "^1.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^1.0.1",
+            "set-blocking": "^2.0.0",
+            "string-width": "^1.0.1",
+            "which-module": "^1.0.0",
+            "window-size": "^0.2.0",
+            "y18n": "^3.2.1",
+            "yargs-parser": "^2.4.1"
+          }
+        },
+        "yargs-parser": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz",
+          "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=",
+          "dev": true,
+          "requires": {
+            "camelcase": "^3.0.0",
+            "lodash.assign": "^4.0.6"
+          }
+        }
+      }
+    },
+    "move-concurrently": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
+      "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+      "dev": true,
+      "requires": {
+        "aproba": "^1.1.1",
+        "copy-concurrently": "^1.0.0",
+        "fs-write-stream-atomic": "^1.0.8",
+        "mkdirp": "^0.5.1",
+        "rimraf": "^2.5.4",
+        "run-queue": "^1.0.3"
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "multicast-dns": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
+      "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
+      "dev": true,
+      "requires": {
+        "dns-packet": "^1.3.1",
+        "thunky": "^1.0.2"
+      }
+    },
+    "multicast-dns-service-types": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
+      "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
+      "dev": true
+    },
+    "nan": {
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.1.tgz",
+      "integrity": "sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==",
+      "dev": true
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+          "dev": true
+        }
+      }
+    },
+    "negotiator": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
       "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
@@ -6074,6 +7389,12 @@
       "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
       "dev": true
     },
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
     "no-case": {
       "version": "2.3.2",
       "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
@@ -6083,6 +7404,15 @@
         "lower-case": "^1.1.1"
       }
     },
+    "node-environment-flags": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.4.tgz",
+      "integrity": "sha512-M9rwCnWVLW7PX+NUWe3ejEdiLYinRpsEre9hMkU/6NS4h+EEulYaDH1gCEZ2gyXsmw+RXYDaV2JkkTNcsPDJ0Q==",
+      "dev": true,
+      "requires": {
+        "object.getownpropertydescriptors": "^2.0.3"
+      }
+    },
     "node-fetch": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz",
@@ -6238,6 +7568,12 @@
         }
       }
     },
+    "nodent-runtime": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/nodent-runtime/-/nodent-runtime-3.2.1.tgz",
+      "integrity": "sha512-7Ws63oC+215smeKJQCxzrK21VFVlCFBkwl0MOObt0HOpVQXs3u483sAmtkF33nNqZ5rSOQjB76fgyPBmAUrtCA==",
+      "dev": true
+    },
     "nopt": {
       "version": "3.0.6",
       "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
@@ -6325,6 +7661,15 @@
       "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
       "dev": true
     },
+    "nwsapi": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.2.tgz",
+      "integrity": "sha512-TQOQNxqEdxVjwgwNZyvKDF0vALmzQKZJEZwE3fZWDb7Ns5Hw6l9PxJTGKOHZGsmf7R6grsOe8lWxI43Clz79zg==",
+      "dev": true,
+      "requires": {
+        "jsdom": "^14.0.0"
+      }
+    },
     "oauth-sign": {
       "version": "0.9.0",
       "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@@ -6374,6 +7719,28 @@
         "isobject": "^3.0.0"
       }
     },
+    "object.assign": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+      "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.2",
+        "function-bind": "^1.1.1",
+        "has-symbols": "^1.0.0",
+        "object-keys": "^1.0.11"
+      }
+    },
+    "object.getownpropertydescriptors": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
+      "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.2",
+        "es-abstract": "^1.5.1"
+      }
+    },
     "object.omit": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
@@ -6457,6 +7824,28 @@
         "last-call-webpack-plugin": "^2.1.2"
       }
     },
+    "optionator": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "dev": true,
+      "requires": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.4",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "wordwrap": "~1.0.0"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+          "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+          "dev": true
+        }
+      }
+    },
     "ora": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/ora/-/ora-1.4.0.tgz",
@@ -6517,12 +7906,24 @@
         "os-tmpdir": "^1.0.0"
       }
     },
+    "p-defer": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+      "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
+      "dev": true
+    },
     "p-finally": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
       "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
       "dev": true
     },
+    "p-is-promise": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz",
+      "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==",
+      "dev": true
+    },
     "p-limit": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
@@ -6632,6 +8033,18 @@
         "json-parse-better-errors": "^1.0.1"
       }
     },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "dev": true
+    },
+    "parse5": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
+      "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
+      "dev": true
+    },
     "parseurl": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
@@ -6750,6 +8163,12 @@
         "find-up": "^2.1.0"
       }
     },
+    "pn": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
+      "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
+      "dev": true
+    },
     "popper.js": {
       "version": "1.14.7",
       "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.7.tgz",
@@ -8852,6 +10271,12 @@
         }
       }
     },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
+    },
     "prepend-http": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
@@ -8898,6 +10323,12 @@
       "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
       "dev": true
     },
+    "progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+      "dev": true
+    },
     "promise-inflight": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@@ -9361,6 +10792,26 @@
         "uuid": "^3.3.2"
       }
     },
+    "request-promise-core": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
+      "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.11"
+      }
+    },
+    "request-promise-native": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz",
+      "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==",
+      "dev": true,
+      "requires": {
+        "request-promise-core": "1.1.2",
+        "stealthy-require": "^1.1.1",
+        "tough-cookie": "^2.3.3"
+      }
+    },
     "require-directory": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -9403,6 +10854,16 @@
         "resolve-from": "^3.0.0"
       }
     },
+    "resolve-dir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+      "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.0",
+        "global-modules": "^1.0.0"
+      }
+    },
     "resolve-from": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
@@ -9468,6 +10929,11 @@
         "aproba": "^1.1.1"
       }
     },
+    "rw": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+      "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q="
+    },
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -9486,8 +10952,7 @@
     "safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "sass-graph": {
       "version": "2.2.4",
@@ -9699,6 +11164,15 @@
       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
       "dev": true
     },
+    "saxes": {
+      "version": "3.1.9",
+      "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.9.tgz",
+      "integrity": "sha512-FZeKhJglhJHk7eWG5YM0z46VHmI3KJpMBAQm3xa9meDvd+wevB5GuBB0wc0exPInZiBBHqi00DbS8AcvCGCFMw==",
+      "dev": true,
+      "requires": {
+        "xmlchars": "^1.3.1"
+      }
+    },
     "schema-utils": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
@@ -10270,6 +11744,12 @@
         "readable-stream": "^2.0.1"
       }
     },
+    "stealthy-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+      "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
+      "dev": true
+    },
     "stream-browserify": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
@@ -10381,6 +11861,12 @@
         "get-stdin": "^4.0.1"
       }
     },
+    "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=",
+      "dev": true
+    },
     "supports-color": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -10404,6 +11890,12 @@
         "whet.extend": "~0.9.9"
       }
     },
+    "symbol-tree": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
+      "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=",
+      "dev": true
+    },
     "tapable": {
       "version": "0.2.9",
       "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz",
@@ -10452,6 +11944,11 @@
         "setimmediate": "^1.0.4"
       }
     },
+    "tiny-cookie": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/tiny-cookie/-/tiny-cookie-1.0.1.tgz",
+      "integrity": "sha1-dTeGB5xkKjw9CyrMrWAPjeEZrCo="
+    },
     "to-arraybuffer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@@ -10519,6 +12016,15 @@
         }
       }
     },
+    "tr46": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+      "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
     "trim-newlines": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
@@ -10567,6 +12073,15 @@
       "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
       "dev": true
     },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "~1.1.2"
+      }
+    },
     "type-is": {
       "version": "1.6.16",
       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
@@ -10946,6 +12461,14 @@
       "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz",
       "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ=="
     },
+    "vue-cookie": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/vue-cookie/-/vue-cookie-1.1.4.tgz",
+      "integrity": "sha1-uLRtESvan5Oi9HAXwu1SgtIGT9o=",
+      "requires": {
+        "tiny-cookie": "^1.0"
+      }
+    },
     "vue-functional-data-merge": {
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-2.0.7.tgz",
@@ -11059,6 +12582,31 @@
       "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
       "dev": true
     },
+    "vuex": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.0.tgz",
+      "integrity": "sha512-mdHeHT/7u4BncpUZMlxNaIdcN/HIt1GsGG5LKByArvYG/v6DvHcOxvDCts+7SRdCoIRGllK8IMZvQtQXLppDYg=="
+    },
+    "w3c-hr-time": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz",
+      "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=",
+      "dev": true,
+      "requires": {
+        "browser-process-hrtime": "^0.1.2"
+      }
+    },
+    "w3c-xmlserializer": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz",
+      "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==",
+      "dev": true,
+      "requires": {
+        "domexception": "^1.0.1",
+        "webidl-conversions": "^4.0.2",
+        "xml-name-validator": "^3.0.0"
+      }
+    },
     "watchpack": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
@@ -11079,6 +12627,12 @@
         "minimalistic-assert": "^1.0.0"
       }
     },
+    "webidl-conversions": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+      "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+      "dev": true
+    },
     "webpack": {
       "version": "3.12.0",
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.12.0.tgz",
@@ -11462,6 +13016,12 @@
         "lodash": "^4.17.5"
       }
     },
+    "webpack-node-externals": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz",
+      "integrity": "sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==",
+      "dev": true
+    },
     "webpack-sources": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz",
@@ -11488,6 +13048,43 @@
       "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
       "dev": true
     },
+    "whatwg-encoding": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+      "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+      "dev": true,
+      "requires": {
+        "iconv-lite": "0.4.24"
+      },
+      "dependencies": {
+        "iconv-lite": {
+          "version": "0.4.24",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+          "dev": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3"
+          }
+        }
+      }
+    },
+    "whatwg-mimetype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+      "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==",
+      "dev": true
+    },
+    "whatwg-url": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
+      "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
+      "dev": true,
+      "requires": {
+        "lodash.sortby": "^4.7.0",
+        "tr46": "^1.0.1",
+        "webidl-conversions": "^4.0.2"
+      }
+    },
     "whet.extend": {
       "version": "0.9.9",
       "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
@@ -11587,6 +13184,18 @@
         "safe-buffer": "~5.1.0"
       }
     },
+    "xml-name-validator": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+      "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
+      "dev": true
+    },
+    "xmlchars": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-1.3.1.tgz",
+      "integrity": "sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==",
+      "dev": true
+    },
     "xtend": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
@@ -11698,6 +13307,214 @@
           "dev": true
         }
       }
+    },
+    "yargs-unparser": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz",
+      "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==",
+      "dev": true,
+      "requires": {
+        "flat": "^4.1.0",
+        "lodash": "^4.17.11",
+        "yargs": "^12.0.5"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "camelcase": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz",
+          "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==",
+          "dev": true
+        },
+        "cliui": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+          "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+          "dev": true,
+          "requires": {
+            "string-width": "^2.1.1",
+            "strip-ansi": "^4.0.0",
+            "wrap-ansi": "^2.0.0"
+          }
+        },
+        "cross-spawn": {
+          "version": "6.0.5",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+          "dev": true,
+          "requires": {
+            "nice-try": "^1.0.4",
+            "path-key": "^2.0.1",
+            "semver": "^5.5.0",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
+        "execa": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+          "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+          "dev": true,
+          "requires": {
+            "cross-spawn": "^6.0.0",
+            "get-stream": "^4.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"
+          }
+        },
+        "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"
+          }
+        },
+        "get-stream": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+          "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+          "dev": true,
+          "requires": {
+            "pump": "^3.0.0"
+          }
+        },
+        "invert-kv": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
+          "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
+          "dev": true
+        },
+        "lcid": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
+          "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
+          "dev": true,
+          "requires": {
+            "invert-kv": "^2.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"
+          }
+        },
+        "mem": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz",
+          "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==",
+          "dev": true,
+          "requires": {
+            "map-age-cleaner": "^0.1.1",
+            "mimic-fn": "^2.0.0",
+            "p-is-promise": "^2.0.0"
+          }
+        },
+        "mimic-fn": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz",
+          "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==",
+          "dev": true
+        },
+        "os-locale": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
+          "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
+          "dev": true,
+          "requires": {
+            "execa": "^1.0.0",
+            "lcid": "^2.0.0",
+            "mem": "^4.0.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
+          "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.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"
+          }
+        },
+        "p-try": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz",
+          "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==",
+          "dev": true
+        },
+        "pump": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+          "dev": true,
+          "requires": {
+            "end-of-stream": "^1.1.0",
+            "once": "^1.3.1"
+          }
+        },
+        "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"
+          }
+        },
+        "yargs": {
+          "version": "12.0.5",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
+          "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
+          "dev": true,
+          "requires": {
+            "cliui": "^4.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^3.0.0",
+            "get-caller-file": "^1.0.1",
+            "os-locale": "^3.0.0",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^1.0.1",
+            "set-blocking": "^2.0.0",
+            "string-width": "^2.0.0",
+            "which-module": "^2.0.0",
+            "y18n": "^3.2.1 || ^4.0.0",
+            "yargs-parser": "^11.1.1"
+          }
+        },
+        "yargs-parser": {
+          "version": "11.1.1",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
+          "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
+          "dev": true,
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
     }
   }
 }
diff --git a/package.json b/package.json
index f38793de07aaf6a7b681ca8d1c939fed395006d8..154057e9ccc9cacc91627a8bbf671b6fb7867fc7 100644
--- a/package.json
+++ b/package.json
@@ -12,10 +12,15 @@
   "dependencies": {
     "bootstrap": "^4.3.1",
     "bootstrap-vue": "^2.0.0-rc.15",
+    "d3": "^5.9.2",
+    "d3-scale-chromatic": "^1.3.3",
     "vue": "^2.6.10",
-    "vue-router": "^3.0.1"
+    "vue-cookie": "^1.1.4",
+    "vue-router": "^3.0.1",
+    "vuex": "^3.1.0"
   },
   "devDependencies": {
+    "@vue/test-utils": "^1.0.0-beta.29",
     "autoprefixer": "^7.1.2",
     "babel-core": "^6.22.1",
     "babel-helper-vue-jsx-merge-props": "^2.0.3",
@@ -32,6 +37,10 @@
     "file-loader": "^1.1.4",
     "friendly-errors-webpack-plugin": "^1.6.1",
     "html-webpack-plugin": "^2.30.1",
+    "jsdom": "^14.0.0",
+    "jsdom-global": "^3.0.2",
+    "mocha": "^6.0.2",
+    "mocha-webpack": "^1.1.0",
     "node-notifier": "^5.1.2",
     "node-sass": "^4.11.0",
     "optimize-css-assets-webpack-plugin": "^3.2.0",
@@ -52,7 +61,8 @@
     "webpack": "^3.6.0",
     "webpack-bundle-analyzer": "^2.9.0",
     "webpack-dev-server": "^2.9.1",
-    "webpack-merge": "^4.1.0"
+    "webpack-merge": "^4.1.0",
+    "webpack-node-externals": "^1.7.2"
   },
   "engines": {
     "node": ">= 6.0.0",
diff --git a/src/App.vue b/src/App.vue
index 8b934f953b0c618e1887b43a849d4872b84a17e2..4156da51e1c194b89f9858a559c42c71ebb911ba 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,19 +1,67 @@
 <template>
   <div id="app">
-    <router-view/>
+    <app-navbar id="navbar" v-if="this.$route.name != 'LandingPage'"/>
+    <transition name="fade" mode="out-in">
+      <router-view v-if="this.$route.name == 'LandingPage'"/>
+      <router-view v-else class="content"/>
+    </transition>
   </div>
 </template>
 
 <script>
+
+import navbar from '@/components/partials/Navbar'
+
 export default {
   name: 'App',
+  components: {
+    'app-navbar': navbar,
+  },
+  mounted() {
+    if(this.$cookie.get('token')) {
+      let fetchData = {
+        method: 'POST',
+        headers: {
+          "Authorization": this.$cookie.get('token'),
+        }
+      }
+
+      fetch(`${this.$store.state.baseUrl}/api/get-user`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          let data = {
+            'token': this.$cookie.get('token'),
+            'id': response.data._id,
+            'name': response.data.name,
+            'role': response.data.role,
+            'pageList': response.page_list
+          }
+          console.log(response)
+          this.$store.commit('setUser', data)
+        }
+      })
+    }
+  }
 }
+
 </script>
 
-<style>
+<style lang="scss">
+@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700,700i');
 #app {
-  font-family: 'Avenir', Helvetica, Arial, sans-serif;
+  font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
+  overflow: hidden;
+
+  #navbar {
+    position: fixed;
+    z-index: 999;
+  }
+}
+
+.content {
+  margin-top : 60px;
 }
 </style>
diff --git a/src/assets/css/style.scss b/src/assets/css/style.scss
index d95e7f316cd7014be12696a47e454ab49d1c37b5..f5af2f1ad78811a9cabfd6c3b59bdd2a61d89d69 100644
--- a/src/assets/css/style.scss
+++ b/src/assets/css/style.scss
@@ -1,2 +1,19 @@
+$primary: #17a2b8;
+
 @import 'node_modules/bootstrap/scss/bootstrap';
 @import 'node_modules/bootstrap-vue/src/index.scss';
+
+.fade-enter-active, .fade-leave-active {
+  transition: all .3s ease;
+}
+.fade-enter, .fade-leave-to {
+  opacity: 0;
+}
+.fade-enter {
+  opacity: 0;
+  transform: translateY(10px);
+}
+.fade-leave-to {
+  opacity: 0;
+  transform: translateY(-10px);
+}
\ No newline at end of file
diff --git a/src/assets/etc/visualisasi.csv b/src/assets/etc/visualisasi.csv
new file mode 100644
index 0000000000000000000000000000000000000000..9b5a05c37e17d30b1528db493ee02fc736c47358
--- /dev/null
+++ b/src/assets/etc/visualisasi.csv
@@ -0,0 +1,5 @@
+id,title,category,amount
+0,Pendapatan,Pendapatan,4000000000000
+1,Biaya Langsung,Biaya Langsung,3000000000000
+2,Biaya Tidak Langsung,Biaya Tidak Langsung,2000000000000
+3,Pembiayaan,Pembiayaan,1000000000000
\ No newline at end of file
diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue
index 1c19f2a399d4735f5a3dd4ae1456f476f3de2fa4..629763357369cbd7fe04719f78abcd99eb7bb36e 100644
--- a/src/components/HelloWorld.vue
+++ b/src/components/HelloWorld.vue
@@ -90,6 +90,9 @@ export default {
     return {
       msg: 'Welcome to Your Vue.js App'
     }
+  },
+  created : function() {
+    this.$store.commit('changed','Jenis Keuangan')
   }
 }
 </script>
diff --git a/src/components/pages/BiayaLangsungPage.vue b/src/components/pages/BiayaLangsungPage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..2e65195f150309c49f0158850cefde5b0d388cba
--- /dev/null
+++ b/src/components/pages/BiayaLangsungPage.vue
@@ -0,0 +1,230 @@
+<template>
+  <b-container>
+    <b-breadcrumb class="bg-light" :items="items"></b-breadcrumb>
+    <h2>ANGGARAN BELANJA LANGSUNG APBD JABAR</h2>
+    <b-row class="justify-content-md-center">
+      <b-col id="visualization" class="bg-light" cols="12">
+        <div id="toggle" v-if="currentData.level == 1">
+          <b-button class="option-toggle float-right" @click="toggleHandler()">
+            <span v-if="toggleData">Tampilan per Dinas</span>
+            <span v-else>Tampilan per urusan</span>
+          </b-button>
+        </div>
+        <visualization 
+          v-bind:src="data"
+          @click-handler="visualizationHandler"
+          ref="viz"
+        />
+      </b-col>
+    </b-row>
+    <b-row class="justify-content-md-center">
+      <b-col cols="12" lg="6">
+        <detail-card  :detailAnggaran='items' />
+      </b-col>
+      <b-col id="anggaran-detail-card" cols="12" lg="6">
+        <simple-card-container-scroll
+          @click-handler="visualizationHandler"
+          :dataBubble='data'
+        />
+      </b-col>
+    </b-row>
+    <b-col id="comments-container" cols="12" lg="8">
+      <comments
+        commentable
+        v-bind:id="this.$route.params.id"
+      />
+    </b-col>  
+  </b-container>
+</template>
+
+<script>
+import SimpleCardContainerScroll from '@/components/partials/SimpleCardContainerScroll'
+import Comments from '@/components/partials/Comments'
+import Visualization from '@/components/partials/Visualization'
+import DetailCard from '@/components/partials/DetailCard'
+
+export default {
+  name: 'BiayaLangsung',
+  components: {
+    'simple-card-container-scroll' : SimpleCardContainerScroll,
+    'comments' : Comments,
+    'visualization' : Visualization,
+    'detail-card' : DetailCard
+  },
+  data() {
+    return {
+      data: [],
+      currentData: {level: 0},
+      items: [],
+      toggleData: false
+    }
+  },
+  methods: {
+    visualizationHandler(idobj) {
+      let id = idobj.$oid
+      this.toggleData = false
+      this.$router.push({ name: 'BiayaLangsungId', params: { id: id } })
+    },
+    getLowestLevel(data) {
+      return data[data.length-1].level
+    },
+    searchData(data, currentData) {
+      for (let i = 0; i < data.length; i++) {
+        if (data[i].level == currentData.level && data[i].text == currentData.name) {
+          return i
+        }
+      }
+      return -1
+    },
+    clearArray(arr) {
+      arr.splice(0, arr.length)
+    },
+    breadcrumbHandler() {
+      // Clear or slice breadcrumb item list depending on the condition
+      if (this.items.length != 0) {
+        if (this.getLowestLevel(this.items) > this.currentData.level) {
+          // If the user visits earlier page, trim the breadcrumb items
+          let i = this.searchData(this.items, this.currentData)
+          if (i != -1)
+            this.items = this.items.slice(0, i)
+          else
+            this.clearArray(this.items)          
+        } else if (this.currentData.level - this.getLowestLevel(this.items) >= 2)
+          // If the user jumps two level after the lowest level
+          // immediately clear all breadcrumb items
+          this.clearArray(this.items)
+      }
+
+      // Automatically append 'Semua Anggaran' when on the topmost level
+      if (this.currentData.level == 1 && this.items.length == 0) {
+        this.items.push({
+          text: 'Semua Anggaran',
+          level: 0,
+          to: { name: 'SemuaAnggaran' }
+        })
+      }
+
+      // Push current item to breadcrumb item list
+      this.items.push({
+        text: this.currentData.name,
+        level: this.currentData.level,
+        value: this.currentData.value,
+        id: this.currentData._id.$oid,
+        active: true
+      })
+
+      // Logic to add routing link to each non-active breadcrumb items
+      if (this.items.length >= 2 && this.items[this.items.length-2].text != "Semua Anggaran") {
+        var item = this.items[this.items.length-2]
+        item.active = false
+        item.to = { name: 'BiayaLangsungId', params: { id: item.id } }
+      }
+    },
+    getData(id, updateBreadcrumbHandler) {
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify({ page_id: id }),
+        headers: { "Content-Type": "application/json" }
+      }
+
+      let url = ''
+      if (this.toggleData)
+        url = `${this.$store.state.baseUrl}/api/page/get-grandchildren`
+      else
+        url = `${this.$store.state.baseUrl}/api/page/get`
+
+      fetch(url, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          this.data = response.subdata.sort(function(a, b) { 
+              return b.value - a.value;
+          })
+          this.currentData = response.data
+          console.log(this.data)
+          if (updateBreadcrumbHandler) this.breadcrumbHandler()
+        }
+      })
+    },
+    getDataFromTop() {
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify({ year: 2019 }),
+        headers: { "Content-Type": "application/json" }
+      }
+
+      fetch(`${this.$store.state.baseUrl}/api/page/get-top`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          this.data = response.subdata
+          this.currentData = response.data
+          this.breadcrumbHandler()
+        }
+      })
+    },
+    toggleHandler() {
+      this.toggleData = !this.toggleData
+      this.getData(this.currentData._id.$oid, false)
+      this.$refs.viz.clear()
+    }
+  },
+  created : function() {
+    this.$store.commit('changed','Anggaran Biaya Langsung')
+    if (!this.$route.params.id) this.getDataFromTop()
+    else this.getData(this.$route.params.id, true)
+  },
+  watch: {
+    $route(to, from) {
+      if (!this.$route.params.id) this.getDataFromTop()
+      else this.getData(this.$route.params.id, true)
+      this.$refs.viz.clear()
+    },
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+h2 {
+  color: $primary;
+  text-shadow: 0 5px 10px rgba(50, 50, 50, 0.25);
+  margin: 10px 10px; 
+}
+
+.container {
+  overflow: hidden;
+
+  #comments-container {
+    margin: 10px auto;
+    max-width: 800px;
+  }
+}
+
+#visualization {
+  height: 50vh;
+
+  #toggle {
+    position: absolute;
+    top: 1rem;
+    right: 1rem;
+    z-index: 3;
+  }
+}
+
+.breadcrumb {
+  height: auto;
+  margin: 10px 0;
+  font-size: 0.9rem;
+  color: white;
+  background: $primary;
+}
+
+.breadcrumb-item + .breadcrumb-item:before {
+  color: #aaa;
+  content: ">>";
+}
+
+</style>
\ No newline at end of file
diff --git a/src/components/pages/BiayaTidakLangsungPage.vue b/src/components/pages/BiayaTidakLangsungPage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..cbb2ae33d5a9f7df37a4b90aeb8b1bff2a0f8062
--- /dev/null
+++ b/src/components/pages/BiayaTidakLangsungPage.vue
@@ -0,0 +1,31 @@
+<template>
+  <div>
+    Biaya Tidak langsung
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'BiayaTidakLangsung',
+  components: {
+
+  },
+  data() {
+    return {
+      
+    }
+  },
+  methods: {
+      
+  },
+  created : function() {
+    this.$store.commit('changed','Anggaran Biaya Tidak Langsung')
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+</style>
\ No newline at end of file
diff --git a/src/components/pages/LandingPage.vue b/src/components/pages/LandingPage.vue
index 1cffe12f90125f4c8b7646b9cba7fd80439a9808..30035b204620fc458bd9ab5a66884c724ddb2ff3 100644
--- a/src/components/pages/LandingPage.vue
+++ b/src/components/pages/LandingPage.vue
@@ -1,21 +1,45 @@
 <template>
-  <v-container fluid>
-    Ashiaap
-  </v-container>
+  <div id="placeholder">
+    <div id="content">
+      <div id="img-container">
+        <img src="https://upload.wikimedia.org/wikipedia/commons/0/07/West_Java_coa.png"/>
+      </div>
+      <h2>
+        Selamat Datang di APBD Elektronik Pemerintah Jawa Barat
+      </h2>
+      <div>
+      <b-dropdown id="ddown1" variant="primary"   text="Pilih Tahun..." class="m-md-2">
+        <b-dropdown-item v-on:click="gotoYear('2016')">2016</b-dropdown-item>
+        <b-dropdown-item v-on:click="gotoYear('2017')">2017</b-dropdown-item>
+        <b-dropdown-item v-on:click="gotoYear('2018')">2018</b-dropdown-item>
+        <b-dropdown-item v-on:click="gotoYear('2019')">2019</b-dropdown-item>
+      </b-dropdown>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
 export default {
-    name: 'LoginPage',
-    components: {
+  name: 'LandingPage',
+  components: {
 
-    },
-    data() {
+  },
+  data() {
+    return {
 
-    },
-    methods: {
-        
     }
+  },
+  methods: {
+    gotoYear : function(year) {
+      // TODO: Redirect to visualization page relevant to the selected year
+      this.$store.commit('setYear', year)
+      this.$router.push('semua-anggaran')
+    }
+  },
+  created : function() {
+    //this.$store.commit('changed','semua-anggaran')
+  }
 }
 </script>
 
@@ -23,4 +47,45 @@ export default {
 <style lang="scss" scoped>
 @import 'src/assets/css/style.scss';
 
+#placeholder {
+  height: 100vh;
+  width: 100vw;
+  display: flex;
+  text-align: center;
+
+  background: linear-gradient(0deg, rgba($primary,1) 0%, rgba($primary,0.75) 50%, rgba($primary,0) 100%),
+      url('https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Gedung-Sate-Trees.jpg/1024px-Gedung-Sate-Trees.jpg');
+  background-size: cover;
+  background-position: center;
+  background-repeat: no-repeat;
+
+  #content {
+    margin: auto;
+    padding: 15px;
+    height: auto;
+    min-width: 300px;
+    width: 30vw;
+    background-color: white;
+    border-radius: 15px;
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
+
+    #img-container {
+      img {
+        width: 50%;
+      }
+    }
+
+    h2 {
+      font-weight: bold;
+      font-size: 1.25rem;
+    }
+
+    @media screen and (max-width: 430px) {
+      h2 {
+        font-size: 1rem;
+      }
+    }
+  }
+}
+
 </style>
\ No newline at end of file
diff --git a/src/components/pages/LoginPage.vue b/src/components/pages/LoginPage.vue
index 9336fe2731e639516e2113cf9579d0dd36203e10..4988bb6ae585d73a5af2c9717e82558b9c79e175 100644
--- a/src/components/pages/LoginPage.vue
+++ b/src/components/pages/LoginPage.vue
@@ -1,21 +1,247 @@
 <template>
-  <v-container fluid>
-    Ini buat login
-  </v-container>
+  <div id="placeholder">
+    <div id="container">
+      <b-card no-body>
+        <b-tabs card>
+          <b-tab title="Masuk" active>
+            <b-alert
+              :show="dismissCountDown"
+              dismissible
+              variant="warning"
+              @dismissed="dismissCountDown=0"
+              @dismiss-count-down="countdownCallback"
+            >
+              {{ errorMessage }}
+            </b-alert>
+            <b-form @submit.prevent="submitLogin">
+              <b-form-group label="Nama Pengguna:">
+                <b-form-input
+                  type="text"
+                  v-model="login.username"
+                  required
+                  placeholder="Masukkan nama pengguna" />
+              </b-form-group>
+
+              <b-form-group label="Kata sandi:">
+                <b-form-input
+                  type="password"
+                  v-model="login.password"
+                  required
+                  placeholder="Masukkan kata sandi" />
+              </b-form-group>
+
+              <b-button @click="submitLogin" type="submit" variant="primary">Masuk</b-button>
+            </b-form>
+          </b-tab>
+          <b-tab title="Daftar">
+            <b-alert
+              :show="dismissCountDown"
+              dismissible
+              variant="warning"
+              @dismissed="dismissCountDown=0"
+              @dismiss-count-down="countdownCallback"
+            >
+              {{ errorMessage }}
+            </b-alert>
+            <b-form>
+              <b-form-group label="NIK/NIP:">
+                <b-form-input
+                  type="text"
+                  v-model="register.nik"
+                  required
+                  placeholder="Masukkan NIK/NIP Anda" />
+              </b-form-group>
+
+              <b-form-group label="Nama Lengkap:">
+                <b-form-input
+                  type="text"
+                  v-model="register.name"
+                  required
+                  placeholder="Masukkan nama lengkap" />
+              </b-form-group>
+
+              <b-form-group label="Nama Pengguna:">
+                <b-form-input
+                  type="text"
+                  v-model="register.username"
+                  required
+                  placeholder="Masukkan nama pengguna" />
+              </b-form-group>
+
+              <b-form-group label="Kata sandi:">
+                <b-form-input
+                  type="password"
+                  v-model="register.password"
+                  required
+                  placeholder="Masukkan kata sandi" />
+              </b-form-group>
+
+              <b-form-group label="Konfirmasi kata sandi:">
+                <b-form-input
+                  type="password"
+                  v-model="register.confirmPassword"
+                  required
+                  placeholder="Masukkan ulang kata sandi" />
+              </b-form-group>
+
+              <b-button @click="submitRegister" variant="primary">Daftar</b-button>
+            </b-form>
+          </b-tab>
+        </b-tabs>
+      </b-card>
+    </div>
+  </div>
 </template>
 
 <script>
 export default {
-    name: 'LoginPage',
-    components: {
+  name: 'LoginPage',
+  components: {
+
+  },
+  data() {
+    return {
+      login: {
+        username: '',
+        password: ''
+      },
+      register: {
+        nik: '',
+        name: '',
+        username: '',
+        password: '',
+        confirmPassword: ''
+      },
+      errorMessage: '',
+      dismissSecs: 5,
+      dismissCountDown: 0
+    }
+  },
+  created : function() {
+    this.$store.commit('changed','Jenis Anggaran')
+  },
+  methods: {
+    submitLogin() {
+      if (this.login.username.length == 0 || this.login.password.length == 0) {
+        this.setErrorMessage("Kata pengguna/sandi wajib diisi")
+        return
+      }
 
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify(
+          {
+            username: this.login.username,
+            password: this.login.password,
+          }
+        ),
+        headers: {
+          "Content-Type": "application/json",
+        }
+      }
+
+      fetch(`${this.$store.state.baseUrl}/api/login`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          this.$cookie.set('token', response.data.token)
+          let data = {
+            'token': response.data.token,
+            'id': response.data.user._id,
+            'name': response.data.user.name,
+            'role': response.data.user.role,
+            'pageList': response.data.page_list
+          }
+          this.$store.commit('setUser', data)
+          this.$router.push({name: 'LandingPage'})
+        } else if(response.status === 404) {
+          this.setErrorMessage('Kata pengguna/sandi salah.')
+        } else {
+          this.setErrorMessage('Tidak dapat masuk. Silakan coba lagi.')
+        }
+      })
+      .catch(error => {
+        this.setErrorMessage('Tidak dapat terhubung dengan server. Mohon periksa koneksi internet dan cobalah beberapa saat lagi.')
+      })
     },
-    data() {
+    submitRegister() {
+      if (this.register.username.length === 0) {
+        this.setErrorMessage("Kata pengguna wajib diisi")
+        return
+      }
+      if (this.register.nik.length === 0) {
+        this.setErrorMessage("NIK wajib diisi")
+        return
+      }
+      if (this.register.name.length === 0) {
+        this.setErrorMessage("Nama lengkap wajib diisi")
+        return
+      }
+      if (this.register.password.length === 0) {
+        this.setErrorMessage("Kata sandi wajib diisi")
+        return
+      }
+      if (this.register.password !== this.register.confirmPassword) {
+        this.setErrorMessage("Kata sandi tidak cocok")
+        return
+      }
+      if (this.register.password !== this.register.confirmPassword) {
+        this.setErrorMessage("Kata sandi tidak cocok")
+        return
+      }
+      
+      let role = 0
+      if (this.register.nik.length === 18)
+        role = 1
+
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify(
+          {
+            username: this.register.username,
+            password: this.register.password,
+            user_id: this.register.nik,
+            name: this.register.name,
+            role: role
+          }
+        ),
+        headers: {
+          "Content-Type": "application/json",
+        }
+      };
 
+      fetch(`${this.$store.state.baseUrl}/api/register`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          this.$cookie.set('token', response.data.token)
+          let data = {
+            'token': response.data.token,
+            'id': this.register.nik,
+            'name': this.register.name,
+            'role': role,
+            'pageList': []
+          }
+          this.$store.commit('setUser', data)
+          this.$router.push({name: 'LandingPage'})
+        } else if (response.status === 500) {
+          this.setErrorMessage('Akun dengan NIK ini sudah dibuat.')
+        } else {
+          this.setErrorMessage('Terjadi kesalahan. Kesalahan: ' + response.message)
+        }
+      })
+      .catch(error => {
+        this.setErrorMessage('Tidak dapat terhubung dengan server. Mohon periksa koneksi internet dan cobalah beberapa saat lagi.')
+      })
     },
-    methods: {
-        
+    countdownCallback(dismissCountDown) {
+      this.dismissCountDown = dismissCountDown
+    },
+    setErrorMessage(message) {
+      this.errorMessage = message
+      this.dismissCountDown = this.dismissSecs
     }
+  }
 }
 </script>
 
@@ -23,4 +249,21 @@ export default {
 <style lang="scss" scoped>
 @import 'src/assets/css/style.scss';
 
+#placeholder {
+  display: flex;
+  padding: 30px 20px;
+
+  #container {
+    height: auto;
+    width: 100%;
+    min-width: 250px;
+    max-width: 500px;
+    margin: auto;
+    border-radius: 5px;
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
+  }
+}
+
+
+
 </style>
\ No newline at end of file
diff --git a/src/components/pages/PanelAdministrator.vue b/src/components/pages/PanelAdministrator.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e8703e0272a8ede9a5239b75c74531c838daa05d
--- /dev/null
+++ b/src/components/pages/PanelAdministrator.vue
@@ -0,0 +1,318 @@
+<template>
+  <div id="placeholder">
+    <div id="container">
+      <b-card no-body>
+        <b-tabs card>
+          <b-tab title="Komentar" active>
+            <b-card no-body>
+            <b-tabs v-model="tabIndex" pills vertical card>
+              <b-tab title="Entri Komentar" disabled/>
+              <b-tab
+                v-for="(item, index) in pageList"
+                :key=item._id.$oid
+                v-bind:title="item.name">
+                <b-tabs v-model="tabIndexInner" content-class="mt-3">
+                  <b-tab title="Belum dibalas" active>
+                    <comments :id="item._id.$oid" :ref="index+'-0'" replyable unreplied/>
+                  </b-tab>
+                  <b-tab title="Semua">
+                    <comments :id="item._id.$oid" :ref="index+'-1'" replyable/>
+                  </b-tab>
+                </b-tabs>
+              </b-tab>
+            </b-tabs>
+            </b-card>
+          </b-tab>
+          <b-tab v-if="this.$store.state.user.role == 2" title="Pengaturan Admin">
+              <table-budget :dataTable='dataTable' :key='dataTable.current_item.admin_name' v-on:changeActivity="updateActivity($event)" v-on:backState="backState()"/>
+          </b-tab>  
+        </b-tabs>
+      </b-card>
+    </div>
+  </div>
+</template>
+
+<script>
+import Comments from '@/components/partials/Comments'
+import TableBudget from '@/components/partials/TableBudget'
+
+
+export default {
+  name: 'PanelAdministrator',
+  components: {
+    'comments' : Comments,
+    'table-budget' : TableBudget
+  },
+  computed: {
+    pageList() {
+      return this.$store.state.user.pageList
+    }
+  },
+  data() {
+    return {
+      currentRow: null,
+      clearedRowPointer: null,
+      modalVisibility: false,
+      totalRows: 1,
+      currentPage: 1,
+      perPage: 15,
+      filter: null,
+      selected: 'urusan',
+      tabIndex: 1,
+      tabIndexInner: 0,
+      fields: ['urusan', 'admin', 'aksi'],
+      urusan : [
+        { judul: "Pendapatan", url: "" },
+        { judul: "Pembiayaan", url: "" },
+        { judul: "Biaya Langsung", url: "" },
+        { judul: "Biaya Tidak Langsung", url: "" },
+      ],
+      items : [
+        { urusan: 'Biaya Langsung', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'Biaya Tak Langsung', admin: 'David Timothy Panjaitan'},
+        { urusan: 'Pembiayaan', admin: '-'},
+        { urusan: 'Pendapatan', admin: '-'},
+        { urusan: 'A', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'B', admin: 'David Timothy Panjaitan'},
+        { urusan: 'C', admin: '-'},
+        { urusan: 'D', admin: '-'},
+        { urusan: 'E', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'F', admin: 'David Timothy Panjaitan'},
+        { urusan: 'G', admin: '-'},
+        { urusan: 'H', admin: '-'},
+        { urusan: 'I', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'J', admin: 'David Timothy Panjaitan'},
+        { urusan: 'K', admin: '-'},
+        { urusan: 'L', admin: '-'},
+        { urusan: 'M', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'N', admin: 'David Timothy Panjaitan'},
+        { urusan: 'O', admin: '-'},
+        { urusan: 'P', admin: '-'},
+        { urusan: 'Q', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'R', admin: 'David Timothy Panjaitan'},
+        { urusan: 'S', admin: '-'},
+        { urusan: 'T', admin: '-'},
+        { urusan: 'U', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'V', admin: 'David Timothy Panjaitan'},
+        { urusan: 'W', admin: '-'},
+        { urusan: 'X', admin: '-'},
+        { urusan: 'Y', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'Z', admin: 'David Timothy Panjaitan'},
+      ],
+      options: [
+      ],
+      dataTable : { 
+          perPage: 10,
+          currentPage: 1,
+          fields : { 
+            activity_name : {
+              label : 'Activity Name',
+              sortable : true,
+            }, 
+            admin_name : {
+              label : 'Admin Name',
+              sortable : true,
+            },
+            actions : {
+              label : 'Actions'
+            }
+          },
+          current_item: {
+            id : 99, activity_name:'current activity', admin_name : 'aaa'
+          },
+          items: [
+            // { id: 1, activity_name: 'A', admin_name: 'Flintstone' },
+            // { id: 2, activity_name: 'B', admin_name: 'Flintstone' },
+            // { id: 3, activity_name: 'C', admin_name: 'Rubbleaskldjf klsajdfklsajdkalskjdfklsjdfalkdflksdj fljslkfjskldfj lksajlkfjsdl ksalksjdfklasjdlkjfs lkdjfklsajfklasklfmasdlkfsj oidfamslkdfmi saldkfmsialfi madlifsm' },
+            // { id: 4, activity_name: 'D', admin_name: 'Rubble' },
+            // { id: 5, activity_name: 'E', admin_name: 'Flintstone' },
+            // { id: 6, activity_name: 'F', admin_name: 'Rubble' },
+            // { id: 7, activity_name: 'G', admin_name: 'Gazzoo' },
+            // { id: 8, activity_name: 'H', admin_name: 'Slate' },
+            // { id: 9, activity_name: 'I', admin_name: 'Slaghoople' },
+            // { id: 10, first_name: 'Ricky', last_name: 'Kennedy' }
+          ],
+          options: [
+            // { value: '0', text: 'Rifo Ahmad Genadi' },
+            // { value: '1', text: 'David Timothy Panjaitan' },
+            // { value: '2', text: 'William Rukmansa' },
+            // { value: '3', text: 'Ricky Kennedy' }
+          ],
+          isNotTop : false,
+      },
+      dataStack : [
+
+      ]
+    }
+  },  
+  created : function() {
+    if (this.$store.state.user.role <= 0) {
+      this.$router.push({name: 'LandingPage'});
+      return
+    }
+    this.totalRows = this.items.length
+    this.$store.commit('changed','Jenis Anggaran')
+    if (this.$store.state.user.role === 2 ) {
+      this.fillAdmin()
+      this.fillDataTable('top')
+    }
+  },
+  watch : {
+    tabIndex() {
+      this['$refs'][(this.tabIndex-1) + '-' + this.tabIndexInner][0]['refreshContent']()
+    },
+    tabIndexInner() {
+      this['$refs'][(this.tabIndex-1) + '-' + this.tabIndexInner][0]['refreshContent']()
+    }
+  },
+  methods: {
+    assignAdmin : function(row) {
+      row.item.admin = this.options[this.selected].text
+      this.switchToggleDetails(null)
+    },
+    clearButtonHandler : function(row) {
+      this.modalVisibility = true
+      this.clearedRowPointer = row
+    },
+    clearAdminHandler : function() {
+      this.clearedRowPointer.item.admin = "-"
+      this.switchToggleDetails(null)
+    },
+    switchToggleDetails : function(newRow) {
+      if (this.currentRow) {
+        this.currentRow.toggleDetails()
+      }
+      if (newRow) {
+        newRow.toggleDetails()
+      }
+      this.currentRow = newRow
+      this.selected = null
+    },
+    filterTrigger(item) {
+      this.totalRows = item.length
+      this.currentPage = 1
+    },
+
+    updateCurrentActivity: function(id, activity_name, admin_name) {
+      this.dataTable.current_item.id = id;
+      this.dataTable.current_item.activity_name = activity_name;
+      this.dataTable.current_item.admin_name = admin_name;
+    },
+
+    updateActivity: function(event) {
+      this.fillDataTable(event.$oid)
+    },
+    fillAdmin : function() {
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify({}),
+        headers: { "Content-Type": "application/json" }
+      }
+
+      fetch(`${this.$store.state.baseUrl}/api/admin/get-all`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          for (var it in response.data) {
+            let temp = {value : 99 , text:'test'}
+            // console.log(response.data[it])
+            temp.value = response.data[it]._id
+            temp.text = response.data[it].name
+            this.dataTable.options.push(temp)
+          }
+        }
+      })
+    },
+    fillDataTable : function(idPage) {
+      if (idPage === 'top') {
+        let fetchData = {
+          method: 'POST',
+          body: JSON.stringify({ year: 2019, return_admin : true }),
+          headers: { "Content-Type": "application/json" }
+        }
+
+        fetch(`${this.$store.state.baseUrl}/api/page/get-top`, fetchData)
+        .then(response => response.json())
+        .then(response => {
+          if(response.status === 200) {
+            this.dataTable.items = []
+            for ( let i =0 ; i < response.subdata.length; i++) {
+              let admin = '--'
+              if (response.admin_subdata[i] !== null) {
+                admin = response.admin_subdata[i].name
+              }
+              this.dataTable.items.push({id:response.subdata[i]._id, activity_name:response.subdata[i].name, admin_name : admin})
+            }
+            this.dataTable.current_item.id = response.data._id.$oid
+            if( response.admin !== null )
+              this.dataTable.current_item.admin_name = response.admin.name
+            else 
+              this.dataTable.current_item.admin_name = '--'
+            this.dataTable.current_item.activity_name = response.data.name
+            
+            this.dataStack.push(idPage);
+          }
+        })
+        this.dataTable.isNotTop = false
+      } else {
+        let fetchData = {
+          method: 'POST',
+          body: JSON.stringify({ page_id: idPage , return_admin : true }),
+          headers: { "Content-Type": "application/json" }
+        }
+
+        fetch(`${this.$store.state.baseUrl}/api/page/get`, fetchData)
+        .then(response => response.json())
+        .then(response => {
+          if(response.status === 200) {
+            this.dataTable.items = []
+            for ( let i =0 ; i < response.subdata.length; i++) {
+              let admin = '--'
+              if (response.admin_subdata[i] !== null) {
+                admin = response.admin_subdata[i].name
+              }
+              this.dataTable.items.push({id:response.subdata[i]._id, activity_name:response.subdata[i].name, admin_name : admin})
+            }
+            this.dataTable.current_item.id = response.data._id.$oid
+            if( response.admin !== null )
+              this.dataTable.current_item.admin_name = response.admin.name
+            else 
+              this.dataTable.current_item.admin_name = '--'
+            this.dataTable.current_item.activity_name = response.data.name
+            this.dataStack.push(idPage);
+
+          }
+        
+        })
+        this.dataTable.isNotTop = true
+      }
+
+    },
+    backState : function() {
+      this.dataStack.pop()
+      let current= this.dataStack.pop()
+      this.fillDataTable(current)
+    }
+
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+#placeholder {
+  padding: 30px 20px;
+
+  #container {
+    height: auto;
+    width: 100%;
+    min-width: 250px;
+    max-width: 1000px;
+    margin: auto;
+    border-radius: 5px;
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/components/pages/PanelBackup.vue b/src/components/pages/PanelBackup.vue
new file mode 100644
index 0000000000000000000000000000000000000000..19984f0bb6c5d1122509b923a4ec87dd13f8f43a
--- /dev/null
+++ b/src/components/pages/PanelBackup.vue
@@ -0,0 +1,277 @@
+<template>
+  <div id="placeholder">
+    <div id="container">
+      <b-card no-body>
+        <b-tabs card>
+          <b-tab title="Komentar" active>
+            <b-card no-body>
+            <b-tabs pills vertical card>
+              <b-tab title="Entri Komentar" disabled/>
+              <b-tab
+                v-for="item in urusan"
+                :key=item.judul
+                v-bind:title="item.judul">
+                <b-tabs content-class="mt-3">
+                  <b-tab title="Belum dibalas" active>
+                    <comments replyable/>
+                  </b-tab>
+                  <b-tab title="Semua">
+                    <comments replyable/>
+                  </b-tab>
+                </b-tabs>
+              </b-tab>
+            </b-tabs>
+            </b-card>
+          </b-tab>
+          <b-tab v-if="this.$store.state.user.role == 2" title="Pengaturan Admin">
+            <!-- Table Pagination + Filter -->
+            <b-pagination
+              v-model="currentPage"
+              :total-rows="totalRows"
+              :per-page="perPage"
+              align="center"
+            />
+            <b-form-input
+              v-model="filter"
+              placeholder="Ketik untuk menyaring urusan/admin..."
+            />
+            <div class="mb-3">
+              <small class="text-muted font-italic">
+                Menampilkan {{ totalRows }} baris urusan
+              </small>
+            </div>
+            <b-table
+              show-empty
+              striped
+              hover
+              stacked="sm"
+              :items="items"
+              :fields="fields"
+              :current-page="currentPage"
+              :per-page="perPage"
+              :filter="filter"
+              @filtered="filterTrigger"
+            >
+              <template slot="aksi" slot-scope="row">
+                <div v-if="row.item.admin === '-'">
+                  <div class="px-1 col-md-6 col-12">
+                    <b-button
+                      @click="switchToggleDetails(row)"
+                      variant="success"
+                      size="sm"
+                      class="w-100"
+                    >
+                      Pasang
+                    </b-button>
+                  </div>
+                </div>
+                <b-row class="mx-0" v-else>
+                  <div class="px-1 col-md-6 col-12">
+                    <b-button
+                      @click="switchToggleDetails(row)"
+                      variant="primary"
+                      size="sm"
+                      class="w-100"
+                    >
+                      Ubah
+                    </b-button>
+                  </div>
+                  <div class="px-1 col-md-6 col-12">
+                    <b-button
+                      @click="clearButtonHandler(row)"
+                      variant="danger"
+                      size="sm"
+                      class="w-100"
+                    >
+                      Kosongkan 
+                    </b-button>
+                  </div>
+                </b-row>
+              </template>
+              <template slot="row-details" slot-scope="row">
+                <b-card
+                  bg-variant="light"
+                >
+                  <small><b>Mohon pilih Admin dari daftar di bawah ini:</b></small>
+                  <b-form-select
+                    v-model="selected"
+                    :options="options"
+                    size="sm"
+                  />
+                  <b-button
+                    @click="assignAdmin(row)"
+                    variant="primary"
+                    size="sm"
+                    class="float-right mt-2 ml-2"
+                  >
+                    Pilih Admin
+                  </b-button>
+                  <b-button
+                    @click="switchToggleDetails(null)"
+                    size="sm"
+                    class="float-right mt-2"
+                  >
+                    Batalkan
+                  </b-button>
+                </b-card>
+              </template>
+              <template slot="empty">
+                <div align="center">Tidak ada data untuk ditampilkan</div>
+              </template>
+              <template slot="emptyfiltered">
+                <div align="center">Data tidak ditemukan</div>
+              </template>
+            </b-table>
+            <b-pagination
+              v-model="currentPage"
+              :total-rows="totalRows"
+              :per-page="perPage"
+              align="center"
+            />
+
+            <!-- Modal Component -->
+            <b-modal
+              id="confirmation-modal"
+              centered
+              title="Konfirmasi"
+              v-model="modalVisibility"
+              ok-title="Kosongkan"
+              cancel-title="Batal"
+              ok-variant="danger"
+              @ok="clearAdminHandler"
+            >
+              <p align="center" class="my-4">
+                Apakah Anda yakin ingin mengosongkan Admin?<br>
+                <b>Tindakan ini tidak dapat diurungkan.</b>
+              </p>
+            </b-modal>
+          </b-tab>
+        </b-tabs>
+      </b-card>
+    </div>
+  </div>
+</template>
+
+<script>
+import Comments from '@/components/partials/Comments'
+
+export default {
+  name: 'PanelAdministrator',
+  components: {
+    'comments' : Comments,
+  },
+  data() {
+    return {
+      currentRow: null,
+      clearedRowPointer: null,
+      modalVisibility: false,
+      totalRows: 1,
+      currentPage: 1,
+      perPage: 15,
+      filter: null,
+      selected: 'urusan',
+      fields: ['urusan', 'admin', 'aksi'],
+      urusan : [
+        { judul: "Pendapatan", url: "" },
+        { judul: "Pembiayaan", url: "" },
+        { judul: "Biaya Langsung", url: "" },
+        { judul: "Biaya Tidak Langsung", url: "" },
+      ],
+      items : [
+        { urusan: 'Biaya Langsung', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'Biaya Tak Langsung', admin: 'David Timothy Panjaitan'},
+        { urusan: 'Pembiayaan', admin: '-'},
+        { urusan: 'Pendapatan', admin: '-'},
+        { urusan: 'A', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'B', admin: 'David Timothy Panjaitan'},
+        { urusan: 'C', admin: '-'},
+        { urusan: 'D', admin: '-'},
+        { urusan: 'E', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'F', admin: 'David Timothy Panjaitan'},
+        { urusan: 'G', admin: '-'},
+        { urusan: 'H', admin: '-'},
+        { urusan: 'I', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'J', admin: 'David Timothy Panjaitan'},
+        { urusan: 'K', admin: '-'},
+        { urusan: 'L', admin: '-'},
+        { urusan: 'M', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'N', admin: 'David Timothy Panjaitan'},
+        { urusan: 'O', admin: '-'},
+        { urusan: 'P', admin: '-'},
+        { urusan: 'Q', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'R', admin: 'David Timothy Panjaitan'},
+        { urusan: 'S', admin: '-'},
+        { urusan: 'T', admin: '-'},
+        { urusan: 'U', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'V', admin: 'David Timothy Panjaitan'},
+        { urusan: 'W', admin: '-'},
+        { urusan: 'X', admin: '-'},
+        { urusan: 'Y', admin: 'Rifo Ahmad Genadi'},
+        { urusan: 'Z', admin: 'David Timothy Panjaitan'},
+      ],
+      options: [
+        { value: '0', text: 'Rifo Ahmad Genadi' },
+        { value: '1', text: 'David Timothy Panjaitan' },
+        { value: '2', text: 'William Rukmansa' },
+        { value: '3', text: 'Ricky Kennedy' }
+      ],
+    }
+  },
+  created : function() {
+    if (this.$store.state.user.role <= 0) {
+      this.$router.push({name: 'LandingPage'});
+      return
+    }
+
+    this.totalRows = this.items.length
+    this.$store.commit('changed','Jenis Anggaran')
+  },
+  methods: {
+    assignAdmin : function(row) {
+      row.item.admin = this.options[this.selected].text
+      this.switchToggleDetails(null)
+    },
+    clearButtonHandler : function(row) {
+      this.modalVisibility = true
+      this.clearedRowPointer = row
+    },
+    clearAdminHandler : function() {
+      this.clearedRowPointer.item.admin = "-"
+      this.switchToggleDetails(null)
+    },
+    switchToggleDetails : function(newRow) {
+      if (this.currentRow) {
+        this.currentRow.toggleDetails()
+      }
+      if (newRow) {
+        newRow.toggleDetails()
+      }
+      this.currentRow = newRow
+      this.selected = null
+    },
+    filterTrigger(item) {
+      this.totalRows = item.length
+      this.currentPage = 1
+    }
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+#placeholder {
+  padding: 30px 20px;
+
+  #container {
+    height: auto;
+    width: 100%;
+    min-width: 250px;
+    max-width: 1000px;
+    margin: auto;
+    border-radius: 5px;
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/components/pages/PembiayaanPage.vue b/src/components/pages/PembiayaanPage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4b7aec2f153fe04a1c79da38ba050afd9cabbd02
--- /dev/null
+++ b/src/components/pages/PembiayaanPage.vue
@@ -0,0 +1,31 @@
+<template>
+  <div>
+    Pembiayaan
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Pembiayaan',
+  components: {
+
+  },
+  data() {
+    return {
+      
+    }
+  },
+  methods: {
+      
+  },
+  created : function() {
+    this.$store.commit('changed','Anggaran Pembiayaan')
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+</style>
\ No newline at end of file
diff --git a/src/components/pages/PendapatanPage.vue b/src/components/pages/PendapatanPage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d14ce62e954f8f0c316e18135e2a1e0d95ec552f
--- /dev/null
+++ b/src/components/pages/PendapatanPage.vue
@@ -0,0 +1,80 @@
+<template>
+  <div class="content">
+    <table-budget :data ='data'/>
+  </div>
+</template>
+
+<script>
+import TableBudget from '@/components/partials/TableBudget'
+
+export default {
+  name: 'Pendapatan',
+  components: {
+    'table-budget' : TableBudget
+  },
+  data() {
+    return {
+      data :{
+        perPage: 5,
+        currentPage: 1,
+        fields : { 
+          activity_name : {
+            label : 'Activity Name',
+            sortable : true,
+          }, 
+          admin_name : {
+            label : 'Admin Name',
+            sortable : true,
+          },
+          actions : {
+            label : 'Actions'
+          }
+        },
+        current_item: {
+          id : 99, activity_name:'current activity', admin_name : '--'
+        },
+        items: [
+          { id: 1, activity_name: 'Aaaaaaaaaaaa', admin_name: 'Flintstone' },
+          { id: 2, activity_name: 'B', admin_name: 'Flintstone' },
+          { id: 3, activity_name: 'C', admin_name: 'Rubbleaskldjf klsajdfklsajdkalskjdfklsjdfalkdflksdj fljslkfjskldfj lksajlkfjsdl ksalksjdfklasjdlkjfs lkdjfklsajfklasklfmasdlkfsj oidfamslkdfmi saldkfmsialfi madlifsm' },
+          { id: 4, activity_name: 'D', admin_name: 'Rubble' },
+          { id: 5, activity_name: 'E', admin_name: 'Flintstone' },
+          { id: 6, activity_name: 'F', admin_name: 'Rubble' },
+          { id: 7, activity_name: 'G', admin_name: 'Gazzoo' },
+          { id: 8, activity_name: 'H', admin_name: 'Slate' },
+          { id: 9, activity_name: 'I', admin_name: 'Slaghoople' },
+          // { id: 10, first_name: 'Ricky', last_name: 'Kennedy' }
+        ],
+      }
+    }
+  },
+  computed: {
+    rows() {
+      return this.items.length
+    }
+  },
+  methods: {
+    changeSeen : function() {
+      this.seen = !this.seen;
+      if(this.rows % 5 !== 0) {
+        var remainder = this.rows % 5;
+        var number_of_blank = 5 - remainder;
+        for(var i=0; i < number_of_blank; i++) {
+          this.items.push({id : '--'  , first_name : '--', last_name: '--' } );
+        }
+      }
+    }
+      
+  },
+  //ini jangan dihapus
+  created : function() {
+    this.$store.commit('changed','Anggaran Pendapatan')
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+</style>
\ No newline at end of file
diff --git a/src/components/pages/SemuaAnggaran.vue b/src/components/pages/SemuaAnggaran.vue
new file mode 100644
index 0000000000000000000000000000000000000000..111d00c59fa278f091c08a4d8bb740a02f94ae5c
--- /dev/null
+++ b/src/components/pages/SemuaAnggaran.vue
@@ -0,0 +1,97 @@
+<template>
+  <b-container>
+    <h2> SEMUA ANGGARAN APBD JABAR</h2>
+    <b-row class="justify-content-md-center">
+      <b-col id="visualization" class="bg-light" cols="12" lg="8">
+        <visualization 
+          v-bind:src="data"
+          @click-handler="handler"
+        />
+      </b-col>
+      <b-col cols="12" lg="4">
+        <simple-card-container
+          :dataBubble="data"
+          @click-handler="handler"
+        />
+      </b-col>
+    </b-row>
+    <div id="comments-container">
+      <comments
+        commentable
+        v-bind:id="this.id"
+      />
+    </div>
+  </b-container>
+</template>
+
+<script>
+import SimpleCardContainer from '@/components/partials/SimpleCardContainer'
+import Comments from '@/components/partials/Comments'
+import Visualization from '@/components/partials/Visualization'
+
+export default {
+  name: 'SemuaAnggaran',
+  components: {
+    'simple-card-container' : SimpleCardContainer,
+    'comments' : Comments,
+    'visualization' : Visualization,
+  },
+  data() {
+    return {
+      data : [],
+      id : ""
+    }
+  },
+  methods: {
+    handler(idobj) {
+      let id = idobj.$oid
+      this.$router.push({ name: 'BiayaLangsungId', params: { id: id } })
+    },
+    getDataFromTop() {
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify({ year: 2019 }),
+        headers: { "Content-Type": "application/json" }
+      }
+
+      fetch(`${this.$store.state.baseUrl}/api/page/get-top`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          this.id = response.data._id.$oid
+          this.data = response.subdata
+        }
+      })
+    },
+  },
+  created : function() {
+    this.$store.commit('changed','Semua Anggaran')
+    this.getDataFromTop()
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+h2 {
+  color: $primary;
+  text-shadow: 0 5px 10px rgba(50, 50, 50, 0.25);
+  margin: 10px 10px; 
+}
+
+.container {
+  overflow-x: hidden;
+
+  #comments-container {
+    margin: 10px auto;
+    max-width: 800px;
+  }
+}
+
+#visualization {
+  min-height: 50vh;
+}
+
+</style>
\ No newline at end of file
diff --git a/src/components/pages/SettingsPage.vue b/src/components/pages/SettingsPage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4f67f2573ebe247c075032e65a2a1ada05feebfa
--- /dev/null
+++ b/src/components/pages/SettingsPage.vue
@@ -0,0 +1,148 @@
+<template>
+  <div id="placeholder">
+    <div id="container">
+      <b-card no-body>
+        <b-tabs card>
+          <b-tab title="Ubah Kata Sandi" active>
+            <b-alert
+              :show="dismissCountDown"
+              dismissible
+              :variant="alertVariant"
+              @dismissed="dismissCountDown=0"
+              @dismiss-count-down="countdownCallback"
+            >
+              {{ message }}
+            </b-alert>
+            <b-form @submit.prevent="submitChangePassword">
+              <b-form-group label="Kata sandi lama:">
+                <b-form-input
+                  type="password"
+                  v-model="changePass.oldPassword"
+                  required
+                  placeholder="Masukkan kata sandi lama" />
+              </b-form-group>
+
+              <b-form-group label="Kata sandi baru:">
+                <b-form-input
+                  type="password"
+                  v-model="changePass.newPassword"
+                  required
+                  placeholder="Masukkan kata sandi baru" />
+              </b-form-group>
+
+              <b-form-group label="Konfirmasi kata sandi baru:">
+                <b-form-input
+                  type="password"
+                  v-model="changePass.confirmPassword"
+                  required
+                  placeholder="Masukkan kata sandi baru" />
+              </b-form-group>
+              <b-button @click="submitChangePassword" type="submit" variant="primary">Ubah Kata Sandi</b-button>
+            </b-form>
+          </b-tab>
+        </b-tabs>
+      </b-card>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'UserSettings',
+  components: {
+
+  },
+  data() {
+    return {
+      changePass: {
+        oldPassword: '',
+        newPassword: '',
+        confirmPassword: ''
+      },
+      message: '',
+      dismissSecs: 15,
+      dismissCountDown: 0,
+      alertVariant: 'danger'
+    }
+  },
+  created : function() {
+    this.$store.commit('changed','Jenis Anggaran')
+  },
+  methods: {
+    submitChangePassword() {
+      if (this.changePass.oldPassword.length === 0) {
+        this.setMessage("Kata sandi lama wajib diisi", 'warning')
+        return
+      }
+      if (this.changePass.newPassword.length === 0) {
+        this.setMessage("Kata sandi baru wajib diisi", 'warning')
+        return
+      }
+      if (this.changePass.newPassword !== this.changePass.confirmPassword) {
+        this.setMessage("Kata sandi baru tidak cocok", 'warning')
+        return
+      }
+
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify(
+          {
+            current_password: this.changePass.oldPassword,
+            new_password: this.changePass.newPassword
+          }
+        ),
+        headers: {
+          "Content-Type": "application/json",
+          "Authorization": this.$store.state.user.token
+        }
+      };
+
+      fetch(`${this.$store.state.baseUrl}/api/change-password`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          this.setMessage('Kata sandi berhasil diubah!', 'success')
+        } else if (response.status === 401) {
+          this.setMessage('Kata sandi lama Anda salah. Silakan masukkan kembali kata sandi lama yang benar.', 'danger')
+        } else {
+          this.setMessage('Terjadi kesalahan. Kesalahan: ' + response.message, 'danger')
+        }
+      })
+      .catch(error => {
+        this.setMessage('Tidak dapat terhubung dengan server. Mohon periksa koneksi internet dan cobalah beberapa saat lagi.', 'danger')
+      })
+    },
+    countdownCallback(dismissCountDown) {
+      this.dismissCountDown = dismissCountDown
+    },
+    setMessage(message, variant) {
+      this.message = message
+      this.alertVariant = variant
+      this.dismissCountDown = this.dismissSecs
+    }
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+#placeholder {
+  display: flex;
+  padding: 30px 20px;
+
+  #container {
+    height: auto;
+    width: 100%;
+    min-width: 250px;
+    max-width: 500px;
+    margin: auto;
+    border-radius: 5px;
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
+  }
+}
+
+
+
+</style>
\ No newline at end of file
diff --git a/src/components/partials/Comments.vue b/src/components/partials/Comments.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e1175d5e8aee716f26998e2da1d426f417c179d3
--- /dev/null
+++ b/src/components/partials/Comments.vue
@@ -0,0 +1,241 @@
+<template>
+  <div id="comments-placeholder">
+    <h4 class="font-weight-bold">Komentar ({{rows}})</h4>
+    <div id="comments-container">
+      <h3
+        class="center text-muted"
+      >
+        {{noticeText}}
+      </h3>
+      <b-card
+        bg-variant="light"
+        class="item"
+        v-for="comment in lists"
+        :key="comment._id.$oid"
+      >
+        <div><small class="font-weight-bold">{{comment.commenter_name}}</small></div>
+        {{comment.comment_text}}
+        <div><small class="text-muted font-italic">{{convertTimestamp(comment.date.$date)}}</small></div>
+        <b-card
+          v-if="comment.hasOwnProperty('reply')"
+          bg-variant="dark"
+          text-variant="white"
+          class="item-reply float-right"
+        >
+          <div><small class="font-weight-bold">Administrator</small></div>
+          {{comment.reply.reply_text}}
+          <div><small class="text-muted font-italic">{{comment.reply.timestamp}}</small></div>
+        </b-card>
+        <div v-else>
+          <b-card
+            v-if="replyable"
+            bg-variant="dark"
+            text-variant="white"
+            class="reply-box float-right"
+          >
+            <b-form-textarea
+              id="textarea"
+              class="reply-textarea"
+              v-model="replyText[comment._id.$oid]"
+              placeholder="Masukkan balasan..."
+              no-resize
+            />
+            <b-button variant="primary" class="float-right mt-2" @click="replyComment(comment._id.$oid)">Kirim</b-button>
+          </b-card>
+        </div>
+      </b-card>
+    </div>
+    <div id="comment-box">
+      <b-pagination
+        v-model="currentPage"
+        :total-rows="rows"
+        :per-page="perPage"
+        align="center"
+      />
+      <div v-if="commentable">
+        <div v-if="this.$store.state.user.token != ''" id="comment-section">
+          <b-form-textarea
+            id="textarea"
+            v-model="text"
+            placeholder="Masukkan komentar..."
+            no-resize
+          />
+          <b-button variant="primary" class="float-right mt-2" @click="addComment">Kirim</b-button>
+        </div>
+        <div v-else>
+          Anda harus <router-link :to="{ name:'LoginPage' }">masuk</router-link> terlebih dahulu sebelum memberikan komentar.
+        </div>
+        <div>
+          <small class="text-muted font-italic">
+            Dengan mengirim komentar, Anda tunduk terhadap UU ITE yang berlaku.
+          </small>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Comments',
+  props: {
+    commentable : Boolean,
+    replyable : Boolean,
+    unreplied : Boolean,
+    id: String
+  },
+  components: {
+    
+  },
+  data() {
+    return {
+      noticeText: "",
+      perPage: 5,
+      currentPage: 1,
+      text: "",
+      replyText: [],
+      data: [],
+    }
+  },
+  computed: {
+    rows() {
+      return this.data.length
+    },
+    lists() {
+      // Return just page of items needed
+      return this.data.slice(
+        (this.currentPage - 1) * this.perPage,
+        this.currentPage * this.perPage
+      )
+    },
+  },
+  methods: {
+    addComment() {
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify({ page_id: this.id, text: this.text }),
+        headers: { "Content-Type": "application/json", "Authorization": this.$store.state.user.token }
+      }
+
+      fetch(`${this.$store.state.baseUrl}/api/comment/add`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          this.refreshContent()
+        }
+      })
+    },
+    replyComment(id) {
+      let fetchData = {
+        method: 'POST',
+        body: JSON.stringify({ comment_id: id, text: this.replyText[id] }),
+        headers: { "Content-Type": "application/json", "Authorization": this.$store.state.user.token }
+      }
+
+      fetch(`${this.$store.state.baseUrl}/api/comment/add-reply`, fetchData)
+      .then(response => response.json())
+      .then(response => {
+        if(response.status === 200) {
+          this.refreshContent()
+        }
+      })
+    },
+    refreshContent() {
+      if(this.id != '') {
+        this.data = []
+        this.noticeText = "Memuat komentar"
+        let fetchData = {
+          method: 'POST',
+          body: JSON.stringify({ page_id: this.id }),
+          headers: { "Content-Type": "application/json" }
+        }
+
+        let url = ""
+        if (this.unreplied)
+          url = `${this.$store.state.baseUrl}/api/comment/get-unreplied`
+        else
+          url = `${this.$store.state.baseUrl}/api/comment/get`
+
+        fetch(url, fetchData)
+        .then(response => response.json())
+        .then(response => {
+          if(response.status === 200) {
+            this.data = response.data
+            if (this.rows == 0) this.noticeText = "Tidak ada komentar"
+            else this.noticeText = ""
+          }
+        })
+      }
+    },
+    convertTimestamp(unix) {
+      let months = ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember']
+      let date = new Date(unix)
+      let year = date.getFullYear()
+      let month = months[date.getMonth()]
+      let day = date.getDate()
+      let hours = date.getHours()
+      let minutes = "0" + date.getMinutes()
+      let seconds = "0" + date.getSeconds()
+      return day + ' ' + month + ' ' + year + ', ' + hours +':'+ minutes.substr(-2) + ':' + seconds.substr(-2) + ' WIB'
+    }
+  },
+  created() {
+    this.refreshContent()
+  },
+  watch: {
+    id(val) {
+      this.refreshContent()
+    }
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+#comments-placeholder {
+  width: 100%;
+  height: 100%;
+
+  #comments-container {
+    height: 60%;
+    padding: 10px;
+    overflow: auto;
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    border-radius: 5px;
+
+    .item {
+      width: 100%;
+      box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
+      margin-bottom: 5px;
+    }
+
+    .item-reply, .reply-box {
+      width: 100%;
+      margin-top: 5px;
+    }
+
+    .item-reply>.card-body {
+      padding: 5px 15px !important;
+    }
+
+    .reply-box>.card-body {
+      padding: 5px !important;
+    }
+
+    .reply-textarea {
+      background-color: #212529;
+      border: 1px solid #212529;
+      color: white;
+    }
+  }
+
+  #comment-box {
+    height: 30%;
+    margin: 5% 0;
+  }
+}
+
+</style>
diff --git a/src/components/partials/DetailCard.vue b/src/components/partials/DetailCard.vue
new file mode 100644
index 0000000000000000000000000000000000000000..29ee08840390d56c213d7dd8fad0d74674e9dfa7
--- /dev/null
+++ b/src/components/partials/DetailCard.vue
@@ -0,0 +1,94 @@
+<template>
+  <div id="placeholder">
+    <h4 class="font-weight-bold title">
+      Hierarki
+    </h4>
+    <b-card 
+      header-text-variant="light"
+      header-tag="header"
+      header-bg-variant="info"
+      bg-variant="light"
+    >
+      <div slot="header" class="text-center px-2 py-1 mb-0"> 
+        <h4>{{ head.text }}</h4> 
+        <h5><b>
+          {{ "Rp "+ head.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') + ',00.-' }} 
+        </b></h5> 
+      </div>
+      <div class="content-anggaran" v-for="data in tail" :key=data.text>
+        <p class="text-center separator">â–¼</p>
+        {{ data.text }}
+        <div class="text-right"><b>
+          {{ "Rp "+ data.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') + ',00.-' }}
+        </b></div>
+        <hr/>
+      </div>
+    </b-card>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: 'DetailCard',
+  props : ['detailAnggaran'],
+  data() {
+    return {
+      head : {
+        text: 'Memuat',
+        value: 0
+      },
+      tail : []
+    }
+  },
+  watch: {
+    detailAnggaran(val) {
+      // Exclude top level when the top level is 'Semua Anggaran'
+      if (val.length > 0 && val[0].text == 'Semua Anggaran') val = val.slice(1, val.length)
+
+      this.head = val[0]
+      this.tail = val.slice(1, val.length)
+    }    
+  }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+#placeholder {
+  padding: 10px;
+}
+
+.card-body {
+  font-size: 1rem;
+  padding: 0 1rem;
+}
+
+.title {
+  color: $primary;
+  text-shadow: 0 5px 10px rgba(50, 50, 50, 0.25);
+}
+
+.card {
+  width : 100%;
+  margin-top : 10px;
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
+}
+
+.card-header {
+  font-size: 1.25rem;
+  padding: 0.2rem;
+}
+
+.separator {
+  color: #00000020;
+  margin-top: -0.45rem;
+  margin-bottom: 0;
+}
+
+hr {
+  margin-bottom: 0;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/partials/Navbar.vue b/src/components/partials/Navbar.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f6782aa113f7b76c3f520c10f13e881d6695718b
--- /dev/null
+++ b/src/components/partials/Navbar.vue
@@ -0,0 +1,115 @@
+<template>
+  <b-navbar id="navbar" toggleable="sm" type="dark" variant="info" fixed="top">
+    <b-container>  
+      <b-navbar-brand>
+        <router-link to="/">
+          APBD JABAR
+        </router-link>
+      </b-navbar-brand>
+
+      <b-navbar-toggle target="nav_collapse" />
+
+      <b-collapse is-nav id="nav_collapse">
+      <!-- Right aligned nav items -->
+      <b-navbar-nav>
+        <b-nav-item-dropdown v-bind:text=state left>
+          <b-dropdown-item v-on:click="gotoPage('SemuaAnggaran')">
+            Semua Anggaran
+          </b-dropdown-item>
+          <b-dropdown-item v-on:click="gotoPage('PendapatanPage')">
+            Anggaran Pendapatan
+          </b-dropdown-item>
+          <b-dropdown-item v-on:click="gotoPage('BiayaLangsung')">
+            Anggaran Biaya Langsung
+          </b-dropdown-item>
+          <b-dropdown-item v-on:click="gotoPage('BiayaTidakLangsung')">
+            Anggaran Biaya Tidak Langsung
+          </b-dropdown-item>
+          <b-dropdown-item v-on:click="gotoPage('Pembiayaan')">
+            Anggaran Pembiayaan
+          </b-dropdown-item>
+        </b-nav-item-dropdown>
+      </b-navbar-nav>
+
+      <b-navbar-nav class="ml-auto">
+        <div v-if="this.$store.state.user.token == ''">
+          <b-nav-item v-on:click="gotoPage('LoginPage')" >
+              <span style="color:white;">Masuk</span>
+          </b-nav-item>
+        </div>
+        <div v-else>
+          <b-nav-item-dropdown v-bind:text=name right>
+            <b-dropdown-item
+              v-if="this.$store.state.user.role > 0"
+              v-on:click="gotoPage('PanelAdministrator')"
+            >
+              Panel Admin
+            </b-dropdown-item>
+            <b-dropdown-item v-on:click="gotoPage('UserSettings')">
+              Pengaturan
+            </b-dropdown-item>
+            <b-dropdown-item v-on:click="logOut()">
+              Keluar
+            </b-dropdown-item>
+          </b-nav-item-dropdown>
+        </div>
+      </b-navbar-nav>
+      </b-collapse>
+    </b-container>
+  </b-navbar>
+</template>
+
+<script>
+
+export default {
+  name: 'Navbar',
+  data () {
+    return {
+      
+    }
+  },
+  computed : {
+    state() {
+      return this.$store.state.pilihan
+    },
+    name() {
+      return this.$store.state.user.name
+    }
+  },
+  methods : {
+    gotoPage(page) {
+      this.$router.push({name: page})
+    },
+    logOut() {
+      this.$cookie.set('token', "");
+      this.$store.commit('clearUser')
+      this.$router.push({name: 'LandingPage'});
+    }
+  },
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+b-nav-item {
+  color: white;
+}
+
+#navbar {
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
+}
+
+li a {
+  text-decoration: none;
+  color : black;
+}
+
+a {
+  text-decoration: none;
+  color : white  ;
+}
+
+.navbar-link span {
+  color : rgba(255,255,255,1) !important;
+}
+</style>
diff --git a/src/components/partials/SimpleCard.vue b/src/components/partials/SimpleCard.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6de2f3fccca0d2fff97ad21b543514905e3f1219
--- /dev/null
+++ b/src/components/partials/SimpleCard.vue
@@ -0,0 +1,67 @@
+<template>
+  <b-col class="px-2" md="6" lg="12" cols="12">
+    <b-card 
+      header-text-variant="light"
+      header-tag="header"
+      header-bg-variant="info"
+      bg-variant="light"
+      @click="passIndex()"
+    >
+      <div slot="header" class="text-left px-2 py-1 mb-0"> 
+        {{ jenisAnggaran }}
+      </div>
+      <div class="content-anggaran text-right">
+        <b>{{ total }}</b>
+      </div>
+      <div class="index">
+        <b>{{ index + 1 }}</b>
+      </div>
+    </b-card>
+  </b-col>
+</template>
+
+<script>
+
+export default {
+  name: 'SimpleCard',
+  props : ['jenisAnggaran','totalAnggaran','index'],
+  data() {
+      return {
+        total : "Rp "+this.totalAnggaran
+      }
+  },
+  methods : {
+    passIndex() {
+      this.$emit('click-handler', this.index)
+    }
+  }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+
+.card-body {
+    font-size: 1.25rem;
+}
+
+.card {
+    width : 100%;
+    margin-top : 10px;
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
+    overflow: hidden;
+    cursor: pointer;
+}
+
+.index {
+  position: absolute;
+  font-size: 8rem;
+  font-style: bold;
+  color: #00000011;
+  bottom: -80px;
+  -webkit-user-select: none; /* Safari */        
+  -moz-user-select: none; /* Firefox */
+  -ms-user-select: none; /* IE10+/Edge */
+  user-select: none; /* Standard */
+}
+</style>
diff --git a/src/components/partials/SimpleCardContainer.vue b/src/components/partials/SimpleCardContainer.vue
new file mode 100644
index 0000000000000000000000000000000000000000..615029e79cb3068533bbf23e7cfc3f71f5a44315
--- /dev/null
+++ b/src/components/partials/SimpleCardContainer.vue
@@ -0,0 +1,42 @@
+<template>
+    <b-row id="content-detail">
+        <simple-card v-for="(data, index) in dataBubble" @click-handler="passData" :key="data.name" :jenisAnggaran="data.name" :index="index" :totalAnggaran="data.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') +
+              ',00.-'"/>
+    </b-row>
+</template>
+
+<script>
+import SimpleCard from './SimpleCard'
+
+export default {
+  name: 'SimpleCardContainer',
+  props: ['dataBubble'],
+  data() {
+      return {
+      }
+  },
+  components: {
+      'simple-card':SimpleCard,
+  },
+  methods : {
+    passData(index) {
+      if (this.dataBubble[index].subdata.length != 0) {
+        window.scrollTo(0, 0);
+        this.$emit('click-handler', this.dataBubble[index]._id)
+      }
+    }
+  },
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+b-col {
+  margin: 0;
+}
+
+
+
+</style>
diff --git a/src/components/partials/SimpleCardContainerScroll.vue b/src/components/partials/SimpleCardContainerScroll.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e78e681283e88211c7e6e62df019789bef04a3ea
--- /dev/null
+++ b/src/components/partials/SimpleCardContainerScroll.vue
@@ -0,0 +1,77 @@
+<template>
+  <div id="placeholder">
+    <h4 class="font-weight-bold title">
+      {{"Detail (" + rows + ")" }}
+    </h4>
+    <b-row id="content-detail">
+        <simple-card class="simple-card" @click-handler="passData" v-for="(data, index) in dataBubble" :key="data._id.$oid" :index="index" :jenisAnggaran="data.name" :totalAnggaran="data.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') +
+              ',00.-'"" />
+    </b-row>
+  </div>
+</template>
+
+<script>
+import SimpleCard from './SimpleCard'
+
+export default {
+  name: 'SimpleCardContainer',
+  props: ['dataBubble'],
+  data() {
+      return {
+      }
+  },
+  computed : {
+    rows() {
+      return this.dataBubble.length;
+    }
+  },
+  components: {
+    'simple-card':SimpleCard,
+  },
+  methods : {
+    passData(index) {
+      if (this.dataBubble[index].subdata.length != 0) {
+        window.scrollTo(0, 0);
+        this.$emit('click-handler', this.dataBubble[index]._id)
+      }
+    }
+  },
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+b-col {
+  margin: 0;
+}
+
+.title {
+  color: $primary;
+  text-shadow: 0 5px 10px rgba(50, 50, 50, 0.25);
+}
+
+#placeholder {
+  width: 100%;
+  padding: 10px;
+  
+  #content-detail {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    border-radius: 5px;
+    padding-top: 20px;   
+    max-height: 500px;
+    padding: 0 10px 10px;
+    overflow-y: auto;
+    -webkit-overflow-scrolling: touch;
+  }
+
+  .simple-card {
+    
+  }
+}
+
+
+
+</style>
diff --git a/src/components/partials/TableBudget.vue b/src/components/partials/TableBudget.vue
new file mode 100644
index 0000000000000000000000000000000000000000..94704fad5404a38c4757b2eef5f6d58535a8f5fe
--- /dev/null
+++ b/src/components/partials/TableBudget.vue
@@ -0,0 +1,265 @@
+<template>
+  <b-container class="content justify-content-center">
+    <b-col>
+      <b-row align-h='left'>
+        <h3>
+          {{ "Activity : " + currentItemActivity }}
+          <br><br>
+          {{"Admin : " + currentItemAdmin}}
+        </h3>
+      </b-row>
+      <b-row v-if="showCard">
+        <b-card >
+          <small><b>Mohon pilih Admin dari daftar di bawah ini:</b></small>
+            <b-form-select
+              v-model="selected"
+              :options="dataTable.options"
+              size="sm"
+            />
+            <b-button
+              @click="updateAdmin()"
+              variant="primary"
+              size="sm"
+              class="float-right mt-2 ml-2"
+            >
+              Pilih Admin
+            </b-button>
+            <b-button
+              v-on:click="changeShowCardState()"
+              size="sm"
+              class="float-right mt-2"
+            >
+              Batalkan
+            </b-button>
+        </b-card>
+      </b-row>
+      <b-row class="my-2" align-h="space-between">
+        <b-col class="pl-0">
+          <b-button v-on:click="backState()" v-if="dataTable.isNotTop" variant="outline-secondary" size="sm"> kembali </b-button>
+        </b-col>
+        <b-col 
+          v-if="dataTable.current_item.admin_name === '--'" 
+          cols="auto"
+        >
+          <b-button
+            v-on:click="changeShowCardState()"
+            variant="success"
+            size="sm"
+          >
+            Pasang Admin
+          </b-button>
+        </b-col>
+        <b-col 
+          v-else
+          cols="auto"
+        >
+
+            
+            <b-button
+              v-on:click="changeShowCardState()"
+              variant="primary"
+              size="sm"
+            >
+              Ubah Admin
+            </b-button>
+            <b-button
+              v-on:click="showModal()"
+              variant="danger"
+              size="sm"
+            >
+              Hapus Admin 
+            </b-button>
+        </b-col>
+
+      </b-row>
+      
+      <b-row align-h='center' class=" justify-content-center overflow-auto">
+          <b-table
+            hover
+            responsive
+            id="my-table"
+            :items="dataTable.items"
+            :per-page="dataTable.perPage"
+            :current-page="dataTable.currentPage"
+            :fields="dataTable.fields"
+            small
+            striped
+            :busy="isBusy"
+            stacked="md"
+            fixed
+          >
+          <div slot="table-busy" class="text-center text-danger my-2">
+            <b-spinner class="align-middle"></b-spinner>
+            <strong>Loading...</strong>
+          </div>
+          <template slot="actions" slot-scope="row" >
+            <b-button 
+              size="sm"
+              v-on:click="seeDetail(row)"  
+            >
+              Lihat
+            </b-button>
+          </template>
+          </b-table>
+
+          <b-pagination
+            v-model="dataTable.currentPage"
+            :total-rows="rows"
+            :per-page="dataTable.perPage"
+            aria-controls="my-table"
+          ></b-pagination>
+      </b-row>
+    </b-col>
+    <!-- Modal Component -->
+    <b-modal
+      id="confirmation-modal"
+      centered
+      title="Konfirmasi"
+      v-model="modalVisibility"
+      ok-title="Hapus"
+      cancel-title="Batal"
+      ok-variant="danger"
+      @ok="removeAdmin()"
+    >
+      <p align="center" class="my-4">
+        Apakah Anda yakin ingin untuk  menghapus Admin?<br>
+        <b>Tindakan ini tidak dapat diurungkan.</b>
+      </p>
+    </b-modal>
+  </b-container>
+</template>
+
+<script>
+export default {
+  name: 'TableBudget',
+  components: {
+
+  },
+  props: ['dataTable'],
+  data() {
+    return {
+      isBusy : false,
+      showCard : false,
+      selected : 0,
+      modalVisibility : false
+    }
+  },
+  watch : {
+    currentItemAdmin() {
+      console.log(currentItemActivity)
+    }
+  },
+  computed: {
+    rows() {
+      return this.dataTable.items.length
+    },
+    currentItemAdmin() {
+      return this.dataTable.current_item.admin_name
+    },
+    currentItemActivity() {
+      return this.dataTable.current_item.activity_name
+    },
+  },
+  methods: {
+    getData : function() {
+      return this.dataTable;
+    },
+    // tambahkan property table
+    // :tbody-tr-class="rowClass"
+
+    rowClass( items, type ) {
+      if(!items) return
+      if(items.admin_name === '--')
+        return 'table-danger'
+      else
+        return 'table-success'
+    },
+
+    changeShowCardState : function() {
+      this.showCard = !this.showCard;
+    },
+
+    removeAdmin : function() {
+      this.dataTable.current_item.admin_name = '--';
+    },
+
+    updateAdmin : function() {
+      if(this.selected === 0) {
+        alert('pilihan tidak valid')
+      } else {
+        let fetchData = {
+          method: 'POST',
+          body: JSON.stringify({page_id : this.dataTable.current_item.id, admin_id: this.selected}),
+          headers: { "Content-Type": "application/json" }
+        }
+    
+        fetch(`${this.$store.state.baseUrl}/api/admin/add-page`, fetchData)
+        .then(response => response.json())
+        .then(response => {
+          if(response.status === 200) {
+              for(let i in this.dataTable.options){
+                if(this.dataTable.options[i].value === this.selected){
+                  this.dataTable.current_item.admin_name = this.dataTable.options[i].text;
+                  break;
+                } 
+              }
+          }
+        })
+
+        // fetchData = {
+        //   method: 'POST',
+        //   body: JSON.stringify({page_id : this.dataTable.current_item.id}),
+        //   headers: { "Content-Type": "application/json" }
+        // }
+    
+        // fetch(`${this.$store.state.baseUrl}/api/admin/get-admin`, fetchData)
+        // .then(response => response.json())
+        // .then(response => {
+        //   if(response.status === 200) {
+        //       console.log(response)
+        //       this.dataTable.current_item.admin_name = response.data.name;
+        //   }
+        // })
+      }
+    },
+    seeDetail : function(row) {
+      // this.isBusy = true
+      console.log('row : ')
+      console.log(row.item.id)
+      this.$emit('changeActivity',row.item.id);
+    },
+    showModal : function() {
+      this.modalVisibility = true;
+    },
+    backState : function() {
+      // this.isBusy = true
+      this.$emit('backState');
+    },
+  },
+  created : function() {
+
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+* {
+  margin: 0%;
+  padding: 0%;
+}
+
+.b-table tbody tr td {
+  cursor: pointer;
+}
+
+.col-auto {
+  padding : 0px 5px;
+}
+
+.card {
+  width: 100%;
+}
+
+</style>
\ No newline at end of file
diff --git a/src/components/partials/Visualization.vue b/src/components/partials/Visualization.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6e43297ed0a1b42b1c289fc81f2b1ad3186376f8
--- /dev/null
+++ b/src/components/partials/Visualization.vue
@@ -0,0 +1,406 @@
+<template>
+  <div id="placeholder">
+    <div id="chart-container" ref="container">
+      <div id="options-container">
+        <h3
+          v-if="!hide"
+          class="text-center text-muted"
+        >
+          Memuat data
+        </h3>
+        <div id="options" v-else>
+          <div v-if="optionHidden">
+            <b-button class="option-toggle" @click="optionHidden = !optionHidden">
+              â–¼
+            </b-button>
+          </div>
+          <div v-else>
+            <div>
+            <b-button class="option-toggle" @click="optionHidden = !optionHidden">
+              â–²
+            </b-button>
+            </div>
+            <div id="option-choice">
+              <b class="mr-3">Tata letak</b>
+              <b-form-group class="mb-0 mr-5">
+                <b-form-radio-group v-model="selected" name="position-options">
+                  <b-form-radio value="normal">Normal</b-form-radio>
+                  <b-form-radio value="sorted">Merata</b-form-radio>
+                  <b-form-radio value="sorted-proportional">Proporsional</b-form-radio>
+                  <b-form-radio value="separated">Pisah</b-form-radio>
+                  <b-form-input v-if="selected == 'separated'" v-model="separator" type="range" :min="0" :max="src.length-1"></b-form-input>
+                </b-form-radio-group>
+              </b-form-group>
+              <b class="mr-3">Warna</b>
+              <b-form-group class="mb-0">
+                <b-form-radio-group v-model="selectedColor" name="color-options">
+                  <b-form-radio value="random">Random</b-form-radio>
+                  <b-form-radio value="valueDependent">Sesuai nilai</b-form-radio>
+                </b-form-radio-group>
+              </b-form-group>
+            </div>
+          </div>
+        </div>
+      </div>
+      <svg id="chart"/>
+      <div id="separator" v-if="selected=='separated'&&hide">
+        <div id="text">
+          <b>{{anggaran}}</b>
+        </div>
+        <div id="line"/>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as d3 from 'd3'
+
+export default {
+  name: 'Visualization',
+  components: {
+
+  },
+  props: ['src'],
+  data() {
+    return {
+      hide: false,
+      svg: null,
+      tooltip: null,
+      simulation: null,
+      selected: 'normal',
+      selectedColor: 'random',
+      radiusCircles: null,
+      maxRadius: 60,
+      minRadius: 3,
+      separator: 0,
+      width: 600,
+      height: 400,
+      columnForColor: "name",
+      columnForWidth: "value",
+      columnId: "_id",
+      columnPercentage: "percentage",
+      columnSubdata: "subdata",
+      ticked: null,
+      optionHidden: true,
+    }
+  },
+  computed: {
+    anggaran() {
+      if (this.src[this.separator])
+        return 'Rp'+this.src[this.separator].value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') +
+                ',00.-'
+      return ''
+    }
+  },
+  mounted() {
+    window.addEventListener("resize", this.sizeHandler)
+    this.width = this.$refs.container.clientWidth
+    this.height = this.$refs.container.clientHeight
+  },
+  destroyed() {
+    window.removeEventListener("resize", this.sizeHandler)
+  },
+  watch: {
+    src(val) {
+      if (this.simulation) this.simulation.stop()
+      this.separator = parseInt(this.src.length/2);
+      this.createChart()
+    },
+    width(val) {
+      this.clear()
+      if (this.simulation) this.simulation.stop()
+      this.createChart()
+    },
+    height(val) {
+      this.clear()
+      if (this.simulation) this.simulation.stop()
+      this.createChart()
+    },
+    selectedColor(val) {
+      this.clear()
+      if (this.simulation) this.simulation.stop()
+      this.createChart()
+    },
+    selected(val) {
+      if (this.simulation) this.simulation.stop()
+      this.setSimulation()
+    },
+    separator(val) {
+      if (this.simulation) this.simulation.stop()
+      this.setSimulation()
+    }
+  },
+  methods: {
+    clear() {
+      if (this.svg) this.svg.selectAll("*").remove()
+      if (this.tooltip) this.tooltip.remove()
+      this.hide = false
+    },
+    createChart() {
+      d3.select("#chart-container").datum(this.src).call(this.bubbleChart());
+      this.hide = true
+    },
+    sizeHandler() {
+      this.height = this.$refs.container.clientHeight
+      this.width = this.$refs.container.clientWidth
+    },
+    setSimulation() {
+      this.simulation = d3.forceSimulation(this.src)
+        .force('charge', d3.forceManyBody().strength((d) => {
+          if (this.selected == 'normal')
+            return -20
+          else
+            return -10
+        }))
+        .force('collision', d3.forceCollide().radius((d) => {
+          return this.radiusCircles(d[this.columnForWidth]) + 1
+        }))
+        .force('x', d3.forceX((d) => {
+          if (this.selected == 'sorted')
+            return this.width*((this.src.length-d.index-1)/this.src.length - 0.5)*0.75
+          else if (this.selected == 'sorted-proportional')
+            return this.width*(this.radiusCircles(d[this.columnForWidth])/this.maxRadius - 0.5)*0.75
+          else if (this.selected == 'normal')
+            return 0
+          else if (this.selected == 'separated')
+            return d.index > this.separator ? -this.width/4 : this.width/4
+        }))
+        .force('y', d3.forceY())
+        .on('tick', this.ticked)
+    },
+    bubbleChart() {
+      var width = this.width,
+      height = this.height,
+      maxRadius = 60,
+      minRadius = 3,
+      columnForColor = "name",
+      columnForWidth = "value",
+      columnId = "_id",
+      columnPercentage = "percentage",
+      columnSubdata = "subdata"
+
+      var self = this
+
+      function chart(selection) {
+        // create chart
+        var data = selection.datum()
+        var div = selection
+        self.svg = div.select("svg")
+        self.svg.attr("width", self.width).attr("height", self.height)
+        
+        //put the data (hidden) to be visible when mouseover
+        self.tooltip = selection
+          .append("div")
+          .style("position", "fixed")
+          .style("z-index", "99")
+          .style("visibility", "hidden")
+          .style("color", "white")
+          .style("padding", "8px")
+          .style("background-color", "#222222cc")
+          .style("border-radius", "6px")
+          .style("text-align", "center")
+          .style("width", "auto")
+          .style("max-width", "400px")
+          .style("box-shadow", "0 5px 10px rgba(0, 0, 0, 0.25)")
+          .text("")
+
+        function validate(x, a, b) {
+          if (x < a) {
+            x = a          
+          }
+          if (x > b) x = b
+          return x
+        }     
+
+        // ticked handler function
+        self.ticked = function(e) {
+
+          node.attr("cx", function(d) {
+              let radius = self.radiusCircles(d[self.columnForWidth])
+              return validate(d.x, -self.width/2+radius, self.width/2-radius)
+            })
+            .attr("cy", function(d) {
+              let radius = self.radiusCircles(d[self.columnForWidth])
+              return validate(d.y, -self.height/2+radius, self.height/2-radius)
+            });
+        }
+
+        //create circles width by data
+        self.radiusCircles = d3.scaleSqrt().domain([d3.min(data, function(d) {
+          return +d[self.columnForWidth]
+        }), d3.max(data, function(d) {
+          return +d[self.columnForWidth]
+        })]).range([self.minRadius,self.maxRadius])
+        
+        //create circle colors by data
+        var colorCircles = d3.scaleOrdinal(d3.schemeCategory10)
+        
+        // make force simulation function
+        self.setSimulation()
+
+        //create the circles
+        var node = self.svg.selectAll("circle")
+          .data(data)
+          .enter()
+          .append("circle")
+          .attr('r', function(d) {
+            return self.radiusCircles(d[self.columnForWidth])
+          })
+          .style("fill", function(d) {
+            if (self.selectedColor == 'valueDependent')
+              return d3.interpolateViridis(self.radiusCircles(d[self.columnForWidth])/self.maxRadius)
+            else if (self.selectedColor == 'random')
+              return colorCircles(d[self.columnForColor])
+          })
+          .style("cursor", "pointer")
+          .attr('transform', 'translate(' + [width / 2, height / 2] + ')')
+
+          // set data visible in mouseover
+          .on("mouseover", function(d) {
+            self.tooltip.html(
+              "<h5 style='margin-bottom: 0;'>" +
+              d[self.columnForColor] +
+              "</h5><b>" +
+              // "<h6 style='margin-bottom: 0;'>" +
+              // d[columnPercentage].toFixed(2) +
+              // "%</h6><b>" +
+              "Rp " +
+              d[self.columnForWidth].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".") +
+              ",00.-</b>"
+            );
+            return self.tooltip.style("visibility", "visible")
+          })
+          .on("mouseup", function(d) {
+            if (d[self.columnSubdata].length != 0) {
+              self.clear()
+              self.$emit('click-handler', d[self.columnId])
+            }
+          })
+          .on("mousemove", function(d) {
+            let yPos = d3.event.pageY - window.scrollY + 2
+            let xPos = (d3.event.pageX)
+            if (xPos < window.innerWidth/2)
+              return self.tooltip.style("top", yPos + "px").style("left", (xPos+10) + "px").style("right", null)
+            else
+              return self.tooltip.style("top", yPos + "px").style("left", null).style("right", (window.innerWidth-xPos-15) + "px")
+          })
+          .on("mouseout", function() {
+            return self.tooltip.style("visibility", "hidden")
+          });
+      }
+
+      chart.width = function(val){
+        if (!arguments) {
+          return self.width
+        } else {
+          self.width = val
+        }
+        return chart
+      }
+
+      chart.height = function(val) {
+        if (!arguments) {
+          return self.height
+        } else {
+          self.height = val
+        }
+        return chart
+      }
+
+      chart.columnForColor = function(value) {
+        if (!arguments.columnForColor) {
+          return self.columnForColor
+        }
+        self.columnForColor = value
+        return chart
+      };
+
+      chart.columnForWidth = function(value) {
+        if (!arguments.columnForWidth) {
+          return self.columnForWidth
+        }
+        self.columnForWidth = value
+        return chart
+      };
+
+      chart.columnId = function(value) {
+        if (!arguments.columnId) {
+          return self.columnId
+        }
+        self.columnId = value
+        return chart
+      };
+      
+      return chart
+    }
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+@import 'src/assets/css/style.scss';
+
+#placeholder {
+  width: 100%;
+  height: 100%;
+
+  #chart-container {
+    display: flex;
+    flex-wrap: wrap;
+    width: 100%;
+    height: 100%;
+
+    #chart {
+      margin: auto;
+      z-index: 1;
+    }
+  }
+
+  #options-container {
+    position: absolute;
+    padding: 1rem;
+    z-index: 2;
+
+    #options {
+      .option-toggle {
+        color: white;
+        margin-bottom: 5px;
+      }
+
+      #option-choice {
+        background-color: #ffffffcc;
+        padding: 1rem;
+      }
+    }
+  }
+
+  #separator {
+    font-size: 1.5rem;
+    display: flex;
+    justify-content: center;
+    position: absolute;
+    width: 100%;
+    height: 100%;
+
+    #text {
+      position: absolute;
+      color: #00000066;
+      z-index: 0;
+      text-align: center;
+      bottom: 0;
+    }
+
+    #line {
+      background-color: #00000066;
+      position: absolute;
+      height: 90%;
+      width: 1px;
+    }
+  }
+
+
+}
+
+</style>
diff --git a/src/components/store/Store.js b/src/components/store/Store.js
new file mode 100644
index 0000000000000000000000000000000000000000..510788d9be0108ec187f9003542928647eb95f5f
--- /dev/null
+++ b/src/components/store/Store.js
@@ -0,0 +1,53 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+Vue.prototype.$store = store
+export const store = new Vuex.Store({
+  state : {
+    pilihan : 'Jenis Keuangan',
+    count : 0,
+    year : 2019,
+    user : {
+      token: '',
+      id: -1,
+      name: '',
+      role: -1,
+      pageList: []
+    },
+    baseUrl: 'http://localhost:5000'
+  },
+  computed: {
+    pilihan() {
+      return this.$store.getters.pilihan
+    }
+  },
+  mutations : {
+    changed(state, pil) {
+      state.pilihan = pil
+    },
+    setYear(state, data) {
+      state.year = data
+    },
+    setUser(state, data) {
+      state.user.token = data.token
+      state.user.id = data.id
+      state.user.name = data.name
+      state.user.role = data.role
+      state.user.pageList = data.pageList
+    },
+    clearUser(state) {
+      state.user.token = '',
+      state.user.id = -1,
+      state.user.name = '',
+      state.user.role = -1,
+      state.user.pageList = []
+    }
+  },
+  getters : {
+    pilihan : (state) => {
+      return this.state.pilihan
+    }
+  }
+    
+})
\ No newline at end of file
diff --git a/src/main.js b/src/main.js
index 9868e451f28bade2f3af204b3dd697a4f932310d..44488f4ae3b2fc2fa48abc7526cd69167af0f869 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,19 +1,28 @@
 // The Vue build version to load with the `import` command
 // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
 import Vue from 'vue'
+import Vuex from 'vuex'
 import App from './App'
 import router from './router'
 import BootstrapVue from 'bootstrap-vue'
+import VueCookie from 'vue-cookie'
+import {store} from './components/store/store'
+ 
 import 'bootstrap/dist/css/bootstrap.css'
 import 'bootstrap-vue/dist/bootstrap-vue.css'
 
 Vue.config.productionTip = false
 Vue.use(BootstrapVue)
+Vue.use(Vuex)
+Vue.use(VueCookie)
 
 /* eslint-disable no-new */
 new Vue({
   el: '#app',
   router,
+  store,
   components: { App },
   template: '<App/>'
 })
+
+
diff --git a/src/router/index.js b/src/router/index.js
index 75398dd39a5fbbc2c123869a906e710ea231a266..fa7d7fa16d106bfe81577a6be161ff45f59a2f61 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -2,7 +2,14 @@ import Vue from 'vue'
 import Router from 'vue-router'
 import LandingPage from '@/components/pages/LandingPage'
 import LoginPage from '@/components/pages/LoginPage'
-
+import Pendapatan from '@/components/pages/PendapatanPage'
+import Pembiayaan from '@/components/pages/PembiayaanPage'
+import BiayaTidakLangsung from '@/components/pages/BiayaTidakLangsungPage'
+import BiayaLangsung from '@/components/pages/BiayaLangsungPage'
+import SemuaAnggaran from '@/components/pages/SemuaAnggaran'
+import SimpleCardContainer from '@/components/partials/SimpleCardContainer'
+import PanelAdministrator from '@/components/pages/PanelAdministrator'
+import UserSettings from '@/components/pages/SettingsPage'
 Vue.use(Router)
 
 export default new Router({
@@ -17,6 +24,51 @@ export default new Router({
       name: 'LoginPage',
       component: LoginPage
     },
+    {
+      path: '/pendapatan',
+      name: 'PendapatanPage',
+      component: Pendapatan
+    },
+    {
+      path: '/biaya-tidak-langsung',
+      name: 'BiayaTidakLangsung',
+      component: BiayaTidakLangsung
+    },
+    {
+      path: '/biaya-langsung',
+      name: 'BiayaLangsung',
+      component: BiayaLangsung
+    },
+    {
+      path: '/biaya-langsung/:id',
+      name: 'BiayaLangsungId',
+      component: BiayaLangsung
+    },
+    {
+      path: '/pembiayaan',
+      name: 'Pembiayaan',
+      component: Pembiayaan
+    },
+    {
+      path: '/semua-anggaran',
+      name: 'SemuaAnggaran',
+      component: SemuaAnggaran
+    },
+    {
+      path: '/tes',
+      name: 'SimpleCardContainer',
+      component: SimpleCardContainer
+    },
+    {
+      path: '/panel-administrator',
+      name: 'PanelAdministrator',
+      component: PanelAdministrator
+    },
+    {
+      path: '/pengaturan',
+      name: 'UserSettings',
+      component: UserSettings
+    },
   ],
   mode: 'history',
 })
diff --git a/src/test/setup.js b/src/test/setup.js
new file mode 100644
index 0000000000000000000000000000000000000000..d1a058b72dbfe007349608f8f2c0bb5230e2981b
--- /dev/null
+++ b/src/test/setup.js
@@ -0,0 +1,11 @@
+// from @vue/cli-plugin-unit-mocha/setup.js
+require('jsdom-global')(undefined, { pretendToBeVisual: true, url: 'http://localhost:8080' })
+
+// https://github.com/vuejs/vue-test-utils/issues/936
+// better fix for "TypeError: Super expression must either be null or
+// a function" than pinning an old version of prettier.
+window.Date = Date
+
+
+require('jsdom-global')()
+global.expect = require('expect')
\ No newline at end of file
diff --git a/src/test/testHelloWorld.spec.js b/src/test/testHelloWorld.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..38c41e509cc724293d8e5a356d7a90c3ab0492d1
--- /dev/null
+++ b/src/test/testHelloWorld.spec.js
@@ -0,0 +1,12 @@
+import {shallow} from '@vue/test-utils'
+import HelloWorld from '../src/components/HelloWorld.vue'
+describe('HelloWorld.vue',function(){
+    
+  it('Checking <h2> tag text',function(){
+      
+      const wrapper = shallow(HelloWorld)
+      const h2= wrapper.find('h2')
+      expect(h2.text()).toBe('Essential Links')
+  
+  })
+})
\ No newline at end of file
diff --git a/test/setup.js b/test/setup.js
new file mode 100644
index 0000000000000000000000000000000000000000..e2fbfe114714a288f6bb442f8c63faa5707da3ba
--- /dev/null
+++ b/test/setup.js
@@ -0,0 +1,3 @@
+require('jsdom-global')()
+
+global.expect = require('expect')
\ No newline at end of file
diff --git a/test/testHelloWorld.spec.js b/test/testHelloWorld.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..38c41e509cc724293d8e5a356d7a90c3ab0492d1
--- /dev/null
+++ b/test/testHelloWorld.spec.js
@@ -0,0 +1,12 @@
+import {shallow} from '@vue/test-utils'
+import HelloWorld from '../src/components/HelloWorld.vue'
+describe('HelloWorld.vue',function(){
+    
+  it('Checking <h2> tag text',function(){
+      
+      const wrapper = shallow(HelloWorld)
+      const h2= wrapper.find('h2')
+      expect(h2.text()).toBe('Essential Links')
+  
+  })
+})
\ No newline at end of file