Giter Site home page Giter Site logo

moduscreateorg / gimbal Goto Github PK

View Code? Open in Web Editor NEW
117.0 9.0 8.0 5.42 MB

Web Performance Auditing tooling

Home Page: https://labs.moduscreate.com/gimbal-web-performance-audit-budgeting

License: MIT License

TypeScript 94.09% JavaScript 1.25% HTML 0.16% Dockerfile 0.46% Shell 4.03%
performance performance-test lighthouse-audits lighthouse react angular vue javascript

gimbal's Introduction

Gimbal - Web Performance Budgeting Automation

npm (scoped) npm CircleCI PRs Welcome MIT Licensed Powered by Modus_Create

Installation | Documentation | Contributing | Code of Conduct | Twitter

Gimbal uses industry-standard audits to analyze application performance. Continuously track performance to ensure your apps are within acceptable 🏎performance budgets.

Gimbal ❤️ CIs like Circle CI, Travis CI, Jenkins, and GitHub Actions.

Getting Started

You can install Gimbal globally using npm or yarn:

# with npm
npm install --global @modus/gimbal

# or with yarn
yarn global add @modus/gimbal

gimbal --help

Now the gimbal is executable throughout your system for any projects you want to audit.

You can also install it to a specific project as a development dependency.

# with npm
npm install --save-dev @modus/gimbal

# or with yarn
yarn add --dev @modus/gimbal

Your project should have been built in order to execute gimbal.

You can execute it via a npm script: (package.json):

{
  "scripts": {
    "audit": "gimbal audit"
  }
}
# with npm
npm run audit

# or with yarn
yarn audit

Configuration

You don't need to Configure Gimbal, but we understand that defaults are optimistic, at least for existing projects that want to introduce performance budgeting.

To ease you be ready to use, let's start with some sample .gimbalrc.yml config files:

  1. Minimal
  2. Minimal with all native audits
  3. Using other audit plugins and more sample configurations

Please, make sure your project was build before executing gimbal.

You may save them as your .gimbalrc.yml file and run gimbal.

1) Minimal sample .gimbalrc.yml config file:

audits:
  - size

configs:
  buildDir: build

2) Minimal sample .gimbalrc.yml config file running all native audits:

audits:
  - size
  - lighthouse
  - heap-snapshot
  - unused-source

configs:
  buildDir: build

3) Sample .gimbalrc.yml config file running audit plugins and more configurations:

Before executing this config file you should install mentioned plugins. For instance:

# with npm
npm install @modus/gimbal-plugin-axe @modus/gimbal-plugin-last-value @modus/gimbal-plugin-sqlite

# or with yarn
yarn add @modus/gimbal-plugin-axe @modus/gimbal-plugin-last-value @modus/gimbal-plugin-sqlite

In case you don't use build as your build directory and an exception raises with an error concerning a nonexistent build directory, please create one and run gimbal again.

Config file:

# Specify audits to run. Also include any plugins (like axe)
audits:
    - axe
    - size
    - lighthouse
    - heap-snapshot
    - unused-source

configs:
  comment:
    # Only show failures in GitHub PR comments.
    # Useful to pinpoint why a build has failed
    onlyFailures: true

  # Heap snapshot settings
  heap-snapshot:
    threshold:
      Documents: 11
      Frames: 5
      JSHeapTotalSize: 13356000
      JSHeapUsedSize: 10068000
      Nodes: 800
      RecalcStyleCount: 15
      LayoutCount: 15

  # Lighthouse settings
  lighthouse:
    skipAudits:
      - uses-http2
      - redirects-http
      - uses-long-cache-ttl
      - uses-text-compression
    outputHtml: artifacts/lighthouse.html
    threshold:
      accessibility: 90
      "best-practices": 92
      performance: 64
      pwa: 52
      seo: 100

  # File and directory size settings
  size:
    - path: ./build/precache-*.js
      maxSize: 10 KB
    - path: ./build/static/js/[0-9]*.chunk.js
      maxSize: 1 MB
    - path: ./build/static/js/*.chunk.js
      maxSize: 1 MB
    - path: ./build/static/js/runtime*.js
      maxSize: 10 KB
    - path: ./build/index.html
      maxSize: 10 KB
    - path: ./build/favicon.ico
      maxSize: 10 KB
    - path: ./build/
      maxSize: 18 MB

  # Unused source settings
  unused-source:
    threshold:
      - path: "**/*(private).*.chunk.css"
        maxSize: 60%
      - path: "**/!(private).*.chunk.css"
        maxSize: 60%
      - path: "**/*([0-9]).*.chunk.js"
        maxSize: 90%
      - path: "**/!([0-9]|main).*.chunk.js"
        maxSize: 45%
      - path: "**/(main).*.chunk.js"
        maxSize: 50%

# Locations of reports. Useful for storing artifacts in CI
outputs:
  # Only show failures in CLI
  cli:
    onlyFailures: true
  html: artifacts/results.html
  json: artifacts/results.json
  markdown: artifacts/results.md

# Plugins
plugins:
  # Compare metrics to last-saved values
  # Install the Last Value plugin with
  #     npm i @modus/gimbal-plugin-last-value --save-dev 
  - plugin: "@modus/gimbal-plugin-last-value"
    saveOnlyOnSuccess: false

  # Save reports to a database. Needed for gimbal-plugin-last-value
  # Install the Sqlite plugin with
  #     npm i @modus/gimbal-plugin-sqlite --save-dev 
  - plugin: "@modus/gimbal-plugin-sqlite"
    lastValue: true

  # Axe a11y audits
  # Install Axe plugin with
  #     npm i @modus/gimbal-plugin-axe --save-dev 
  - plugin: "@modus/gimbal-plugin-axe"
    thresholds:
      aria-allowed-attr: critical
      color-contrast: serious
      landmark-one-main: moderate
      landmark-complementary-is-top-level: moderate
      meta-viewport: critical
      region: moderate
      page-has-heading-one: moderate
      scrollable-region-focusable: moderate

CI Integration

Consult with our docs for sample CI configuration files:

Docker

Docker images are available in Docker Hub as moduscreate/gimbal.

Packages

This repo is organized as a monorepo that uses Lerna. Packages:

Questions and Support

If you have a problem running Gimbal, please submit an issue. The more information you give us the faster we can get back with a good answer.

How to Improve Web Application Speed and Increase Revenue with Gimbal

How to Improve Web Application Speed and Increase Revenue with Gimbal

Manage UI Performance Budgets with Gimbal

Manage UI Performance Budgets with Gimbal

How to Develop High Performing Web Applications

How to Develop High Performing Web Applications

Modus Create

Modus Create is a digital product consultancy. We use a distributed team of the best talent in the world to offer a full suite of digital product design-build services; ranging from consumer facing apps, to digital migration, to agile development training, and business transformation.

Modus Create

This project is part of Modus Labs.

Modus Labs

Licensing

This project is MIT licensed.

gimbal's People

Contributors

ahsanayaz avatar gonzalezlrjesus avatar grgur avatar kelchm avatar mitchellsimoens avatar obscurerichard avatar rafaelbernard avatar rpigu-i avatar slemmon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gimbal's Issues

Parallel execution

Things should be optimized where we can split out multiple worker threads to allow modules (per #3) could be executed in parallel. If we use hooks (per #4) this may present a problem but only a technical issue that could likely be overcome.

Unused source truncates paths incorrectly

Describe the bug
If there are non-localhost assets on the page, the paths do not correctly get truncated.

To Reproduce
Steps to reproduce the behavior:

  1. Run the unused-source command on modir
  2. See log paths with '...' in front of it

Expected behavior

https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.HTbwNpj0SNk.O/m=signin2/rt=j/sv=1/d=1/ed=1/am=wQE/rs=AGLTcCOGs9O9_yfL5s-45L9xsQebDV1-Nw/cb=gapi.loaded_0 should get truncated to something smaller. The URL matching is incorrect, should rely on the url node module instead of regex.

Add a column to the CLI output to show the threshold

Right now, the commands output a table with two columns. The second column shows the value of that row but if there is a failure this isn't enough to know who failed or why.

We could add a 3rd column to show the threshold for that row but we also need to show if the value needs to be above or below the threshold.

Doing this, we need to take into account not having a super wide table.

Unit testing

We need to decide on a unit testing module.

My preference is jest.

Templating system

We need a mechanism by which to manage the output for each module into each of our desired output formats.

Detect if executed from VCS in a CI and comment on a PR/commit

We need to come up with a way to detect if this is being executed from a VCS (like a GitHub PR) that will likely mean it's in a CI. TravisCI, CircleCI, Jenkins, Gitlab, BitBucket and Buddy have built-in environment variables that can be used.

We should prioritize working with CircleCI but also support TravisCI and setup the means to support n different CIs (Jenkins, Buddy, Gitlab for example) for in the future.

This work will be needed for when we want to comment on a PR and commit. modir has support for CircleCI commenting on a GitHub PR/commit which is our primary focus right now.

Publish to npm

Depended upon #28

Need to build and publish to the npm repo. Need to decide if we want to automatically publish on every master branch merge or on a feature branch or on a tag.

[WIP] Build directory size module

A module should be created (per #3) that will return the size of the build folder in a tabular form.

Using --json flag, the tool will return the same content in JSON format

Response object (JSON):

{
  buildDirectory: {
    name: "Build directory size",
    value: 213134353, // size in bytes
    threshold: 500000000, // comes from the config. Defaults to null
    help: "Helpful info here" // we will use this in the future to give tips on
  }
}

The tabular view should return the following

Audit Value Tip
Build directory size 213.34 MB Helpful info here

Account for objects / trace / errors / classes in logger output

When logging objects and errors, we may want to format it (especially when indented). For objects/arrays, JSON.stringify would be enough (careful when not logging it out as one line) else you would just see Object {} or [object Object]. For errors, basically parsing the stack trace to print that. For other complex things, check if toString is present and log that out.

Logging

Right now, we just use console.log and while that's ok, we need to have different log levels (like verbose) and logs designated to what is logging it out.

There are different modules that can be used (debug, loglevel) along with more indepth modules (winston, bunyan, good comparison on these). Or a custom class which isn't hard for the uses we need and I have built this before a couple times.

We need to evaluate which would suit us now and, if not too much work now, in the future. I think debug is enough but I like the simplicity of loglevel. If loglevel is what we go with, we can still support named output like debug supports. debug doesn't support log levels per se but that doesn't mean we couldn't support that either. debug does have formatters and even custom formatters whereas loglevel is meant to be much more simple so you'd have to format it on your own, once again, not a deal breaker since we could overcome that.

winston and bunyan are normally more for application logging and can have different transports for like piping error logs to an error service. For GaaS we could enable a transport to send logs to the service for output displaying there.

We could use the event emitter from #54 to log out events and their data very easily since the emitter supports glob syntax.

Build Directory Size

Build directory size module should be created as seen (per #3). The module should return the size of the build in a tabular form and in json when the --json flag is used.

Create a test react app

We need to have a script in package.json that can create a test react app. This directory needs to be ignored in .gitignore and the vscode launch configs need to be updated to target it. This will help keep people on the same page also.

Of course document the script in README.md.

Move Config to gimbal-core

So that any module can use the Config class, we should move it to gimbal-core. gimbal-core can be a dependency of another module (like one of the plugins) but gimbal itself is not going to be a dependency. There shouldn't be any issues with moving it to gimbal-core other than changing the imports in gimbal and gimbal already depends on gimbal-core.

Enable logger levels / allowedLevel to be pulled from the config file

Configs for this file (like $allowedLevel) could be run off env var and/or the config file. For config file, can use Config.get('configs.logger'). I would say the config file takes precedence over an env var tho: let $allowedLevel: string = Config.get('configs.logger.level', process.env.GIMBAL_LOG_LEVEL); May want to abstract the config handling to a function to support other configs like the indent level. const config = Config.get('configs.logger'); if (config) { handleConfig(config) }.

Setup CI for this repo

We need to setup CircleCI (or alike) for this repo to run linting and unit tests and eventually publish to npm.

If we do decide on monorepo (per #5) then this complicates things but not in any too difficult to solve issues. Just something to keep in mind.

SQLite and MySQL plugins should be moved to own module

The reason going to a monorepo (#5) was to prevent gimbal from having bloat from builtin plugins that wouldn't be used. To complete this, the two plugins (sqlite and mysql) need to be moved to own module (within the packages dir) including the depended node modules of course.

Serve module should check for directory existence

Right now, if you create a CRA app and run Gimbal on it, the serve module will attempt to serve the build directory that will not exist. The serve module should check it's existence and fail if not present.

Make threshold checking optional

Is your feature request related to a problem? Please describe.
Gimbal always checks thresholds and this is great except there are times I want the checking to be skipped.

Describe the solution you'd like
A config and/or cli option to skip threshold checking. Also would not need to show the threshold and success columns in the outputs.

Config system

There will be multiple things that will need configuration. We can have sensible defaults but will always need to enable projects to configure things. We should support multiple formats like yml, json and javascript.

Create docker image

Right now for CircleCI, I had to have this jobs config:

  gimbal:
    docker:
      - image: circleci/node:latest-browsers

    working_directory: ~/repo

    steps:
      - checkout
      - restore_cache: *restore-dist-cache

      - run:
          name: Setup npm
          command: |
            printf "@modus:registry=https://npm.modus.app\n//npm.modus.app/:_authToken=\"%s\"" "$MODUS_NPM_TOKEN" >> ~/.npmrc
            npm set prefix=/home/circleci/npm
            echo 'export PATH=/home/circleci/npm/bin:$PATH' >> $BASH_ENV
            source $BASH_ENV

      - run:
          name: Install Gimbal
          command: npm install -g @modus/gimbal

      - run:
          name: Run Gimbal
          command: |
            source $BASH_ENV
            gimbal

There are some important pieces here. First, the docker image is CircleCI's node image which runs under the circleci user. This user does have sudo privilege but where npm wants to default install global modules, the user does not have permission for so sudo is required. TO not do that, I changed where npm installs modules to which caused some sourcing too. Also for puppeteer, I had to use the :latest-browsers docker tagged image even though puppeteer installs it's own chrome, it just has some other things installed that is needed at the OS level.

Suffice to say, I think we can make this much easier to to use and a custom docker image may be something we want to use.

Enhance unused source thresholds

Right now, there is a single threshold for the unused source module. Sure, this single threshold can accept 3 different values but that one threshold is run against all files.

This is limiting and not flexible enough. Instead, we need to work like the file/dir size checker module where it accepts a glob and multiple entries each with it's own max size threshold.

Command pass/fail

Right now, we do not have a single way to fail a command. Other than the size checking commands, there is no failing at all.

PR #25 allows to throw an error in a command and that then allows the process to exit with code 1 and logs out the error. This may be enough.

If it's not enough like if we want to still be able to output reports then maybe we want to rely on what is returned and have a "REST" like response with { success: boolean, data: any} or alike.

Common module return format

We have decided that we cannot just work with the raw output from different modules when we want to render things whether that be in the CLI or via a report rendered in HTML or Markdown. We need a generic format or set of formats.

For example, the lighthouse module outputs thousands of lines of JSON where we only actually need one object. Even that object isn't in a format that is similar to other modules. Each module will need to then parse the raw report it generates and format it in this new common output. We can keep the raw report and opt-in/out to having it in the output (like when the JSON output writes to the file).

Sample:

{
  "success": true,
  "data": [
    {
      "success": true,
      "label": "foo.js",
      "rawLabel": "foo.js",
      "value": "12.3 KB",
      "rawValue": 12345,
      "threshold": "13 KB",
      "rawThreshold": 13000,
      "thresholdLimit": "upper"
    },
    {
      "success": true,
      "label": "Unused Source",
      "children": [
        {
          "success": true,
          "label": "foo.js",
          "rawLabel": "foo.js",
          "value": "12.3 KB",
          "rawValue": 12345,
          "threshold": "13 KB",
          "rawThreshold": 13000,
          "thresholdLimit": "upper"
        }
      ]
    }
  ],
  "raw": {},
  "error": {
    "message": "....",
    "stack": [
      "..."
    ]
  }
}

Notes:

  • label could be changed to a different name, was just a term I thought labels that item
  • Notice the second item in the data array also has children so there is nesting.
    • This is for commands that want a single output yet support multiple modules like the cra command.
    • The label then would span across all columns.
    • success in a parent would be based on all child items and shown under all items in a table and spanned across all columns and right aligned.
  • There are two fields for a value and threshold so we only need to parse once. For example, the threshold is likely to be provided as a friendly string like 13 KB instead of the number of bytes yet the size checking will use the numbers to compare.
  • threshold_limit is either upper or lower saying the value should be below (threshold is an upper limit) or above (threshold is a lower limit) the threshold.
  • The error object would contain the message and a parsed stack trace.
  • rawLabel, rawThreshold, rawValue and thresholdLimit are camelCase because of ESLint rule wants it, so didn't want to fight it.
  • rawLabel is because we may want to parse (like truncating paths) the label.

Concerns:

  • This is mainly targeted at an array of data to produce a table or list. Is that all we would need? Is there more?

License

We need to choose what license is appropriate, like MIT or alike.

Mismatch command throws an error

Describe the bug
I made a typo and got an error instead of the help screen.

To Reproduce
Steps to reproduce the behavior:

  1. Execute gimbal help (instead of gimbal --help)
  2. See error

Expected behavior
A message that the command was not found and then the help screen should be shown.

Phases

We need to defined phases of execution and what happens within each. Some phases that may be needed are setup, teardown, reporting.

Analyze bundles

CRA has deprecated Webpack Bundle Analyzer in favor of Source Map Explorer.

Let's see what we can learn from the bundles and sourcemaps

const path = require('path')
const fs = require('fs')
const explore = require('source-map-explorer')

const buildDir = path.join(__dirname, 'build', 'static', 'js')

fs.readdir(buildDir, (err, files) => {
  if (err) {
    return console.log(`Where's the CRA build directory? ` + err)
  }

  const output = files
    .filter(file => file.match(/^(?!runtime).*\.(js)$/))
    .map(bundle => {
      try {
        // SME will complain if sourcemaps contain just one file, but we don't control that
        // in bundles generated by 3rd parties like webpack runtime or Ionic
        const explored = explore(path.resolve(buildDir, bundle))
        return { bundle, ...explored }
      } catch (e) {
        return false;
      }
    })
    .filter(Boolean)

  console.log(output)
})

Stock CRA Output

[
   {
      "bundle":"2.34b4fde6.chunk.js",
      "totalBytes":118776,
      "unmappedBytes":130,
      "files":{
         "react/index.js":45,
         "object-assign/index.js":947,
         "react-dom/index.js":253,
         "react/cjs/react.production.min.js":6488,
         "react-dom/cjs/react-dom.production.min.js":106129,
         "scheduler/index.js":46,
         "scheduler/cjs/scheduler.production.min.js":4603,
         "webpack/buildin/global.js":135,
         "<unmapped>":130
      }
   },
   {
      "bundle":"main.1befcbd7.chunk.js",
      "totalBytes":1118,
      "unmappedBytes":123,
      "files":{
         "logo.svg":224,
         "App.js":420,
         "serviceWorker.js":281,
         "index.js":70,
         "<unmapped>":123
      }
   }
]

MoDir Output

[
   {
      "bundle":"100.981df429.chunk.js",
      "totalBytes":18932,
      "unmappedBytes":138,
      "files":{
         "build/xt9bb6qm.sc.entry.js":14514,
         "polyfills/tslib.js":1763,
         "build/chunk-7c632336.js":1027,
         "build/chunk-6d7d2f8c.js":1490,
         "<unmapped>":138
      }
   },
   {
      "bundle":"101.2fd71d03.chunk.js",
      "totalBytes":32377,
      "unmappedBytes":140,
      "files":{
         "build/fokfxvfn.entry.js":22420,
         "polyfills/tslib.js":1763,
         "build/chunk-6d7d2f8c.js":1520,
         "build/chunk-f56eaea8.js":6534,
         "<unmapped>":140
      }
   },
   {
      "bundle":"148.608a301a.chunk.js",
      "totalBytes":6425,
      "unmappedBytes":138,
      "files":{
         "build/xgnma4yj.sc.entry.js":3527,
         "polyfills/tslib.js":1763,
         "build/chunk-7c632336.js":997,
         "<unmapped>":138
      }
   },
   {
      "bundle":"15.802a14e9.chunk.js",
      "totalBytes":317752,
      "unmappedBytes":132,
      "files":{
         "react/index.js":47,
         "@babel/runtime/helpers/esm/extends.js":269,
         "react-router/esm/react-router.js":6773,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/defineProperty.js":182,
         "@babel/runtime/helpers/esm/inheritsLoose.js":157,
         "tiny-invariant/dist/tiny-invariant.esm.js":143,
         "resolve-pathname/index.js":655,
         "value-equal/index.js":691,
         "history/esm/history.js":8530,
         "babel-preset-react-app/node_modules/@babel/runtime/regenerator/index.js":47,
         "lodash-es/isArray.js":29,
         "lodash-es/_root.js":94,
         "lodash-es/_Symbol.js":11,
         "lodash-es/_getRawTag.js":206,
         "lodash-es/_objectToString.js":64,
         "lodash-es/_baseGetTag.js":143,
         "lodash-es/isObjectLike.js":54,
         "lodash-es/isSymbol.js":79,
         "lodash-es/_isKey.js":228,
         "lodash-es/isObject.js":79,
         "lodash-es/isFunction.js":177,
         "lodash-es/_coreJsData.js":26,
         "lodash-es/_isMasked.js":136,
         "lodash-es/_toSource.js":128,
         "lodash-es/_baseIsNative.js":307,
         "lodash-es/_getValue.js":48,
         "lodash-es/_getNative.js":55,
         "lodash-es/_nativeCreate.js":21,
         "lodash-es/_hashClear.js":57,
         "lodash-es/_hashDelete.js":88,
         "lodash-es/_hashGet.js":173,
         "lodash-es/_hashHas.js":108,
         "lodash-es/_hashSet.js":134,
         "lodash-es/_Hash.js":213,
         "lodash-es/_listCacheClear.js":48,
         "lodash-es/eq.js":49,
         "lodash-es/_assocIndexOf.js":81,
         "lodash-es/_listCacheDelete.js":144,
         "lodash-es/_listCacheGet.js":76,
         "lodash-es/_listCacheHas.js":50,
         "lodash-es/_listCacheSet.js":106,
         "lodash-es/_ListCache.js":217,
         "lodash-es/_Map.js":14,
         "lodash-es/_mapCacheClear.js":89,
         "lodash-es/_isKeyable.js":118,
         "lodash-es/_getMapData.js":96,
         "lodash-es/_mapCacheDelete.js":73,
         "lodash-es/_mapCacheGet.js":45,
         "lodash-es/_mapCacheHas.js":45,
         "lodash-es/_mapCacheSet.js":96,
         "lodash-es/_MapCache.js":217,
         "lodash-es/memoize.js":330,
         "lodash-es/_memoizeCapped.js":99,
         "lodash-es/_stringToPath.js":252,
         "lodash-es/_arrayMap.js":100,
         "lodash-es/_baseToString.js":208,
         "lodash-es/toString.js":44,
         "lodash-es/_castPath.js":57,
         "lodash-es/_toKey.js":105,
         "lodash-es/_baseGet.js":109,
         "lodash-es/get.js":102,
         "@ionic/core/dist/esm/es5/build/chunk-90d954cd.js":298,
         "@ionic/core/dist/esm/es5/build/chunk-f54563a4.js":1508,
         "react-dom/index.js":253,
         "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js":181,
         "webpack/buildin/global.js":148,
         "prop-types/index.js":49,
         "react-router-dom/esm/react-router-dom.js":3063,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/slicedToArray.js":87,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/arrayWithHoles.js":41,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/iterableToArrayLimit.js":236,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/nonIterableRest.js":87,
         "ionicons/dist/ionicons/svg/ios-add-circle-outline.svg":82,
         "ionicons/dist/ionicons/svg/ios-add-circle.svg":74,
         "ionicons/dist/ionicons/svg/ios-add.svg":67,
         "ionicons/dist/ionicons/svg/ios-airplane.svg":72,
         "ionicons/dist/ionicons/svg/ios-alarm.svg":69,
         "ionicons/dist/ionicons/svg/ios-albums.svg":70,
         "ionicons/dist/ionicons/svg/ios-alert.svg":69,
         "ionicons/dist/ionicons/svg/ios-american-football.svg":81,
         "ionicons/dist/ionicons/svg/ios-analytics.svg":73,
         "ionicons/dist/ionicons/svg/ios-aperture.svg":72,
         "ionicons/dist/ionicons/svg/ios-apps.svg":68,
         "ionicons/dist/ionicons/svg/ios-appstore.svg":72,
         "ionicons/dist/ionicons/svg/ios-archive.svg":71,
         "ionicons/dist/ionicons/svg/ios-arrow-back.svg":74,
         "ionicons/dist/ionicons/svg/ios-arrow-down.svg":74,
         "ionicons/dist/ionicons/svg/ios-arrow-dropdown-circle.svg":85,
         "ionicons/dist/ionicons/svg/ios-arrow-dropdown.svg":78,
         "ionicons/dist/ionicons/svg/ios-arrow-dropleft-circle.svg":85,
         "ionicons/dist/ionicons/svg/ios-arrow-dropleft.svg":78,
         "ionicons/dist/ionicons/svg/ios-arrow-dropright-circle.svg":86,
         "ionicons/dist/ionicons/svg/ios-arrow-dropright.svg":79,
         "ionicons/dist/ionicons/svg/ios-arrow-dropup-circle.svg":83,
         "ionicons/dist/ionicons/svg/ios-arrow-dropup.svg":76,
         "ionicons/dist/ionicons/svg/ios-arrow-forward.svg":77,
         "ionicons/dist/ionicons/svg/ios-arrow-round-back.svg":80,
         "ionicons/dist/ionicons/svg/ios-arrow-round-down.svg":80,
         "ionicons/dist/ionicons/svg/ios-arrow-round-forward.svg":83,
         "ionicons/dist/ionicons/svg/ios-arrow-round-up.svg":78,
         "ionicons/dist/ionicons/svg/ios-arrow-up.svg":72,
         "ionicons/dist/ionicons/svg/ios-at.svg":66,
         "ionicons/dist/ionicons/svg/ios-attach.svg":70,
         "ionicons/dist/ionicons/svg/ios-backspace.svg":73,
         "ionicons/dist/ionicons/svg/ios-barcode.svg":71,
         "ionicons/dist/ionicons/svg/ios-baseball.svg":72,
         "ionicons/dist/ionicons/svg/ios-basket.svg":70,
         "ionicons/dist/ionicons/svg/ios-basketball.svg":74,
         "ionicons/dist/ionicons/svg/ios-battery-charging.svg":80,
         "ionicons/dist/ionicons/svg/ios-battery-dead.svg":76,
         "ionicons/dist/ionicons/svg/ios-battery-full.svg":76,
         "ionicons/dist/ionicons/svg/ios-beaker.svg":70,
         "ionicons/dist/ionicons/svg/ios-bed.svg":67,
         "ionicons/dist/ionicons/svg/ios-beer.svg":68,
         "ionicons/dist/ionicons/svg/ios-bicycle.svg":71,
         "ionicons/dist/ionicons/svg/ios-bluetooth.svg":73,
         "ionicons/dist/ionicons/svg/ios-boat.svg":68,
         "ionicons/dist/ionicons/svg/ios-body.svg":68,
         "ionicons/dist/ionicons/svg/ios-bonfire.svg":71,
         "ionicons/dist/ionicons/svg/ios-book.svg":68,
         "ionicons/dist/ionicons/svg/ios-bookmark.svg":72,
         "ionicons/dist/ionicons/svg/ios-bookmarks.svg":73,
         "ionicons/dist/ionicons/svg/ios-bowtie.svg":70,
         "ionicons/dist/ionicons/svg/ios-briefcase.svg":73,
         "ionicons/dist/ionicons/svg/ios-browsers.svg":72,
         "ionicons/dist/ionicons/svg/ios-brush.svg":69,
         "ionicons/dist/ionicons/svg/ios-bug.svg":67,
         "ionicons/dist/ionicons/svg/ios-build.svg":69,
         "ionicons/dist/ionicons/svg/ios-bulb.svg":68,
         "ionicons/dist/ionicons/svg/ios-bus.svg":67,
         "ionicons/dist/ionicons/svg/ios-business.svg":72,
         "ionicons/dist/ionicons/svg/ios-cafe.svg":68,
         "ionicons/dist/ionicons/svg/ios-calculator.svg":74,
         "ionicons/dist/ionicons/svg/ios-calendar.svg":72,
         "ionicons/dist/ionicons/svg/ios-call.svg":68,
         "ionicons/dist/ionicons/svg/ios-camera.svg":70,
         "ionicons/dist/ionicons/svg/ios-car.svg":67,
         "ionicons/dist/ionicons/svg/ios-card.svg":68,
         "ionicons/dist/ionicons/svg/ios-cart.svg":68,
         "ionicons/dist/ionicons/svg/ios-cash.svg":68,
         "ionicons/dist/ionicons/svg/ios-cellular.svg":72,
         "ionicons/dist/ionicons/svg/ios-chatboxes.svg":73,
         "ionicons/dist/ionicons/svg/ios-chatbubbles.svg":75,
         "ionicons/dist/ionicons/svg/ios-checkbox-outline.svg":80,
         "ionicons/dist/ionicons/svg/ios-checkbox.svg":72,
         "ionicons/dist/ionicons/svg/ios-checkmark-circle-outline.svg":88,
         "ionicons/dist/ionicons/svg/ios-checkmark-circle.svg":80,
         "ionicons/dist/ionicons/svg/ios-checkmark.svg":73,
         "ionicons/dist/ionicons/svg/ios-clipboard.svg":73,
         "ionicons/dist/ionicons/svg/ios-clock.svg":69,
         "ionicons/dist/ionicons/svg/ios-close-circle-outline.svg":84,
         "ionicons/dist/ionicons/svg/ios-close-circle.svg":76,
         "ionicons/dist/ionicons/svg/ios-close.svg":69,
         "ionicons/dist/ionicons/svg/ios-cloud-circle.svg":76,
         "ionicons/dist/ionicons/svg/ios-cloud-done.svg":74,
         "ionicons/dist/ionicons/svg/ios-cloud-download.svg":78,
         "ionicons/dist/ionicons/svg/ios-cloud-outline.svg":77,
         "ionicons/dist/ionicons/svg/ios-cloud-upload.svg":76,
         "ionicons/dist/ionicons/svg/ios-cloud.svg":69,
         "ionicons/dist/ionicons/svg/ios-cloudy-night.svg":76,
         "ionicons/dist/ionicons/svg/ios-cloudy.svg":70,
         "ionicons/dist/ionicons/svg/ios-code-download.svg":77,
         "ionicons/dist/ionicons/svg/ios-code-working.svg":76,
         "ionicons/dist/ionicons/svg/ios-code.svg":68,
         "ionicons/dist/ionicons/svg/ios-cog.svg":67,
         "ionicons/dist/ionicons/svg/ios-color-fill.svg":74,
         "ionicons/dist/ionicons/svg/ios-color-filter.svg":76,
         "ionicons/dist/ionicons/svg/ios-color-palette.svg":77,
         "ionicons/dist/ionicons/svg/ios-color-wand.svg":74,
         "ionicons/dist/ionicons/svg/ios-compass.svg":71,
         "ionicons/dist/ionicons/svg/ios-construct.svg":73,
         "ionicons/dist/ionicons/svg/ios-contact.svg":71,
         "ionicons/dist/ionicons/svg/ios-contacts.svg":72,
         "ionicons/dist/ionicons/svg/ios-contract.svg":72,
         "ionicons/dist/ionicons/svg/ios-contrast.svg":72,
         "ionicons/dist/ionicons/svg/ios-copy.svg":68,
         "ionicons/dist/ionicons/svg/ios-create.svg":70,
         "ionicons/dist/ionicons/svg/ios-crop.svg":68,
         "ionicons/dist/ionicons/svg/ios-cube.svg":68,
         "ionicons/dist/ionicons/svg/ios-cut.svg":67,
         "ionicons/dist/ionicons/svg/ios-desktop.svg":71,
         "ionicons/dist/ionicons/svg/ios-disc.svg":68,
         "ionicons/dist/ionicons/svg/ios-document.svg":72,
         "ionicons/dist/ionicons/svg/ios-done-all.svg":72,
         "ionicons/dist/ionicons/svg/ios-download.svg":72,
         "ionicons/dist/ionicons/svg/ios-easel.svg":69,
         "ionicons/dist/ionicons/svg/ios-egg.svg":67,
         "ionicons/dist/ionicons/svg/ios-exit.svg":68,
         "ionicons/dist/ionicons/svg/ios-expand.svg":70,
         "ionicons/dist/ionicons/svg/ios-eye-off.svg":71,
         "ionicons/dist/ionicons/svg/ios-eye.svg":67,
         "ionicons/dist/ionicons/svg/ios-fastforward.svg":75,
         "ionicons/dist/ionicons/svg/ios-female.svg":70,
         "ionicons/dist/ionicons/svg/ios-filing.svg":70,
         "ionicons/dist/ionicons/svg/ios-film.svg":68,
         "ionicons/dist/ionicons/svg/ios-finger-print.svg":76,
         "ionicons/dist/ionicons/svg/ios-fitness.svg":71,
         "ionicons/dist/ionicons/svg/ios-flag.svg":68,
         "ionicons/dist/ionicons/svg/ios-flame.svg":69,
         "ionicons/dist/ionicons/svg/ios-flash-off.svg":73,
         "ionicons/dist/ionicons/svg/ios-flash.svg":69,
         "ionicons/dist/ionicons/svg/ios-flashlight.svg":74,
         "ionicons/dist/ionicons/svg/ios-flask.svg":69,
         "ionicons/dist/ionicons/svg/ios-flower.svg":70,
         "ionicons/dist/ionicons/svg/ios-folder-open.svg":75,
         "ionicons/dist/ionicons/svg/ios-folder.svg":70,
         "ionicons/dist/ionicons/svg/ios-football.svg":72,
         "ionicons/dist/ionicons/svg/ios-funnel.svg":70,
         "ionicons/dist/ionicons/svg/ios-gift.svg":68,
         "ionicons/dist/ionicons/svg/ios-git-branch.svg":74,
         "ionicons/dist/ionicons/svg/ios-git-commit.svg":74,
         "ionicons/dist/ionicons/svg/ios-git-compare.svg":75,
         "ionicons/dist/ionicons/svg/ios-git-merge.svg":73,
         "ionicons/dist/ionicons/svg/ios-git-network.svg":75,
         "ionicons/dist/ionicons/svg/ios-git-pull-request.svg":80,
         "ionicons/dist/ionicons/svg/ios-glasses.svg":71,
         "ionicons/dist/ionicons/svg/ios-globe.svg":69,
         "ionicons/dist/ionicons/svg/ios-grid.svg":68,
         "ionicons/dist/ionicons/svg/ios-hammer.svg":70,
         "ionicons/dist/ionicons/svg/ios-hand.svg":68,
         "ionicons/dist/ionicons/svg/ios-happy.svg":69,
         "ionicons/dist/ionicons/svg/ios-headset.svg":71,
         "ionicons/dist/ionicons/svg/ios-heart-dislike.svg":77,
         "ionicons/dist/ionicons/svg/ios-heart-empty.svg":75,
         "ionicons/dist/ionicons/svg/ios-heart-half.svg":74,
         "ionicons/dist/ionicons/svg/ios-heart.svg":69,
         "ionicons/dist/ionicons/svg/ios-help-buoy.svg":73,
         "ionicons/dist/ionicons/svg/ios-help-circle-outline.svg":83,
         "ionicons/dist/ionicons/svg/ios-help-circle.svg":75,
         "ionicons/dist/ionicons/svg/ios-help.svg":68,
         "ionicons/dist/ionicons/svg/ios-home.svg":68,
         "ionicons/dist/ionicons/svg/ios-hourglass.svg":73,
         "ionicons/dist/ionicons/svg/ios-ice-cream.svg":73,
         "ionicons/dist/ionicons/svg/ios-image.svg":69,
         "ionicons/dist/ionicons/svg/ios-images.svg":70,
         "ionicons/dist/ionicons/svg/ios-infinite.svg":72,
         "ionicons/dist/ionicons/svg/ios-information-circle-outline.svg":90,
         "ionicons/dist/ionicons/svg/ios-information-circle.svg":82,
         "ionicons/dist/ionicons/svg/ios-information.svg":75,
         "ionicons/dist/ionicons/svg/ios-jet.svg":67,
         "ionicons/dist/ionicons/svg/ios-journal.svg":71,
         "ionicons/dist/ionicons/svg/ios-key.svg":67,
         "ionicons/dist/ionicons/svg/ios-keypad.svg":70,
         "ionicons/dist/ionicons/svg/ios-laptop.svg":70,
         "ionicons/dist/ionicons/svg/ios-leaf.svg":68,
         "ionicons/dist/ionicons/svg/ios-link.svg":68,
         "ionicons/dist/ionicons/svg/ios-list-box.svg":72,
         "ionicons/dist/ionicons/svg/ios-list.svg":68,
         "ionicons/dist/ionicons/svg/ios-locate.svg":70,
         "ionicons/dist/ionicons/svg/ios-lock.svg":68,
         "ionicons/dist/ionicons/svg/ios-log-in.svg":70,
         "ionicons/dist/ionicons/svg/ios-log-out.svg":71,
         "ionicons/dist/ionicons/svg/ios-magnet.svg":70,
         "ionicons/dist/ionicons/svg/ios-mail-open.svg":73,
         "ionicons/dist/ionicons/svg/ios-mail-unread.svg":75,
         "ionicons/dist/ionicons/svg/ios-mail.svg":68,
         "ionicons/dist/ionicons/svg/ios-male.svg":68,
         "ionicons/dist/ionicons/svg/ios-man.svg":67,
         "ionicons/dist/ionicons/svg/ios-map.svg":67,
         "ionicons/dist/ionicons/svg/ios-medal.svg":69,
         "ionicons/dist/ionicons/svg/ios-medical.svg":71,
         "ionicons/dist/ionicons/svg/ios-medkit.svg":70,
         "ionicons/dist/ionicons/svg/ios-megaphone.svg":73,
         "ionicons/dist/ionicons/svg/ios-menu.svg":68,
         "ionicons/dist/ionicons/svg/ios-mic-off.svg":71,
         "ionicons/dist/ionicons/svg/ios-mic.svg":67,
         "ionicons/dist/ionicons/svg/ios-microphone.svg":74,
         "ionicons/dist/ionicons/svg/ios-moon.svg":68,
         "ionicons/dist/ionicons/svg/ios-more.svg":68,
         "ionicons/dist/ionicons/svg/ios-move.svg":68,
         "ionicons/dist/ionicons/svg/ios-musical-note.svg":76,
         "ionicons/dist/ionicons/svg/ios-musical-notes.svg":77,
         "ionicons/dist/ionicons/svg/ios-navigate.svg":72,
         "ionicons/dist/ionicons/svg/ios-notifications-off.svg":81,
         "ionicons/dist/ionicons/svg/ios-notifications-outline.svg":85,
         "ionicons/dist/ionicons/svg/ios-notifications.svg":77,
         "ionicons/dist/ionicons/svg/ios-nuclear.svg":71,
         "ionicons/dist/ionicons/svg/ios-nutrition.svg":73,
         "ionicons/dist/ionicons/svg/ios-open.svg":68,
         "ionicons/dist/ionicons/svg/ios-options.svg":71,
         "ionicons/dist/ionicons/svg/ios-outlet.svg":70,
         "ionicons/dist/ionicons/svg/ios-paper-plane.svg":75,
         "ionicons/dist/ionicons/svg/ios-paper.svg":69,
         "ionicons/dist/ionicons/svg/ios-partly-sunny.svg":76,
         "ionicons/dist/ionicons/svg/ios-pause.svg":69,
         "ionicons/dist/ionicons/svg/ios-paw.svg":67,
         "ionicons/dist/ionicons/svg/ios-people.svg":70,
         "ionicons/dist/ionicons/svg/ios-person-add.svg":74,
         "ionicons/dist/ionicons/svg/ios-person.svg":70,
         "ionicons/dist/ionicons/svg/ios-phone-landscape.svg":79,
         "ionicons/dist/ionicons/svg/ios-phone-portrait.svg":78,
         "ionicons/dist/ionicons/svg/ios-photos.svg":70,
         "ionicons/dist/ionicons/svg/ios-pie.svg":67,
         "ionicons/dist/ionicons/svg/ios-pin.svg":67,
         "ionicons/dist/ionicons/svg/ios-pint.svg":68,
         "ionicons/dist/ionicons/svg/ios-pizza.svg":69,
         "ionicons/dist/ionicons/svg/ios-planet.svg":70,
         "ionicons/dist/ionicons/svg/ios-play-circle.svg":75,
         "ionicons/dist/ionicons/svg/ios-play.svg":68,
         "ionicons/dist/ionicons/svg/ios-podium.svg":70,
         "ionicons/dist/ionicons/svg/ios-power.svg":69,
         "ionicons/dist/ionicons/svg/ios-pricetag.svg":72,
         "ionicons/dist/ionicons/svg/ios-pricetags.svg":73,
         "ionicons/dist/ionicons/svg/ios-print.svg":69,
         "ionicons/dist/ionicons/svg/ios-pulse.svg":69,
         "ionicons/dist/ionicons/svg/ios-qr-scanner.svg":74,
         "ionicons/dist/ionicons/svg/ios-quote.svg":69,
         "ionicons/dist/ionicons/svg/ios-radio-button-off.svg":80,
         "ionicons/dist/ionicons/svg/ios-radio-button-on.svg":79,
         "ionicons/dist/ionicons/svg/ios-radio.svg":69,
         "ionicons/dist/ionicons/svg/ios-rainy.svg":69,
         "ionicons/dist/ionicons/svg/ios-recording.svg":73,
         "ionicons/dist/ionicons/svg/ios-redo.svg":68,
         "ionicons/dist/ionicons/svg/ios-refresh-circle.svg":78,
         "ionicons/dist/ionicons/svg/ios-refresh.svg":71,
         "ionicons/dist/ionicons/svg/ios-remove-circle-outline.svg":85,
         "ionicons/dist/ionicons/svg/ios-remove-circle.svg":77,
         "ionicons/dist/ionicons/svg/ios-remove.svg":70,
         "ionicons/dist/ionicons/svg/ios-reorder.svg":71,
         "ionicons/dist/ionicons/svg/ios-repeat.svg":70,
         "ionicons/dist/ionicons/svg/ios-resize.svg":70,
         "ionicons/dist/ionicons/svg/ios-restaurant.svg":74,
         "ionicons/dist/ionicons/svg/ios-return-left.svg":75,
         "ionicons/dist/ionicons/svg/ios-return-right.svg":76,
         "ionicons/dist/ionicons/svg/ios-reverse-camera.svg":78,
         "ionicons/dist/ionicons/svg/ios-rewind.svg":70,
         "ionicons/dist/ionicons/svg/ios-ribbon.svg":70,
         "ionicons/dist/ionicons/svg/ios-rocket.svg":70,
         "ionicons/dist/ionicons/svg/ios-rose.svg":68,
         "ionicons/dist/ionicons/svg/ios-sad.svg":67,
         "ionicons/dist/ionicons/svg/ios-save.svg":68,
         "ionicons/dist/ionicons/svg/ios-school.svg":70,
         "ionicons/dist/ionicons/svg/ios-search.svg":70,
         "ionicons/dist/ionicons/svg/ios-send.svg":68,
         "ionicons/dist/ionicons/svg/ios-settings.svg":72,
         "ionicons/dist/ionicons/svg/ios-share-alt.svg":73,
         "ionicons/dist/ionicons/svg/ios-share.svg":69,
         "ionicons/dist/ionicons/svg/ios-shirt.svg":69,
         "ionicons/dist/ionicons/svg/ios-shuffle.svg":71,
         "ionicons/dist/ionicons/svg/ios-skip-backward.svg":77,
         "ionicons/dist/ionicons/svg/ios-skip-forward.svg":76,
         "ionicons/dist/ionicons/svg/ios-snow.svg":68,
         "ionicons/dist/ionicons/svg/ios-speedometer.svg":75,
         "ionicons/dist/ionicons/svg/ios-square-outline.svg":78,
         "ionicons/dist/ionicons/svg/ios-square.svg":70,
         "ionicons/dist/ionicons/svg/ios-star-half.svg":73,
         "ionicons/dist/ionicons/svg/ios-star-outline.svg":76,
         "ionicons/dist/ionicons/svg/ios-star.svg":68,
         "ionicons/dist/ionicons/svg/ios-stats.svg":69,
         "ionicons/dist/ionicons/svg/ios-stopwatch.svg":73,
         "ionicons/dist/ionicons/svg/ios-subway.svg":70,
         "ionicons/dist/ionicons/svg/ios-sunny.svg":69,
         "ionicons/dist/ionicons/svg/ios-swap.svg":68,
         "ionicons/dist/ionicons/svg/ios-switch.svg":70,
         "ionicons/dist/ionicons/svg/ios-sync.svg":68,
         "ionicons/dist/ionicons/svg/ios-tablet-landscape.svg":80,
         "ionicons/dist/ionicons/svg/ios-tablet-portrait.svg":79,
         "ionicons/dist/ionicons/svg/ios-tennisball.svg":74,
         "ionicons/dist/ionicons/svg/ios-text.svg":68,
         "ionicons/dist/ionicons/svg/ios-thermometer.svg":75,
         "ionicons/dist/ionicons/svg/ios-thumbs-down.svg":75,
         "ionicons/dist/ionicons/svg/ios-thumbs-up.svg":73,
         "ionicons/dist/ionicons/svg/ios-thunderstorm.svg":76,
         "ionicons/dist/ionicons/svg/ios-time.svg":68,
         "ionicons/dist/ionicons/svg/ios-timer.svg":69,
         "ionicons/dist/ionicons/svg/ios-today.svg":69,
         "ionicons/dist/ionicons/svg/ios-train.svg":69,
         "ionicons/dist/ionicons/svg/ios-transgender.svg":75,
         "ionicons/dist/ionicons/svg/ios-trash.svg":69,
         "ionicons/dist/ionicons/svg/ios-trending-down.svg":77,
         "ionicons/dist/ionicons/svg/ios-trending-up.svg":75,
         "ionicons/dist/ionicons/svg/ios-trophy.svg":70,
         "ionicons/dist/ionicons/svg/ios-tv.svg":66,
         "ionicons/dist/ionicons/svg/ios-umbrella.svg":72,
         "ionicons/dist/ionicons/svg/ios-undo.svg":68,
         "ionicons/dist/ionicons/svg/ios-unlock.svg":70,
         "ionicons/dist/ionicons/svg/ios-videocam.svg":72,
         "ionicons/dist/ionicons/svg/ios-volume-high.svg":75,
         "ionicons/dist/ionicons/svg/ios-volume-low.svg":74,
         "ionicons/dist/ionicons/svg/ios-volume-mute.svg":75,
         "ionicons/dist/ionicons/svg/ios-volume-off.svg":74,
         "ionicons/dist/ionicons/svg/ios-walk.svg":68,
         "ionicons/dist/ionicons/svg/ios-wallet.svg":70,
         "ionicons/dist/ionicons/svg/ios-warning.svg":71,
         "ionicons/dist/ionicons/svg/ios-watch.svg":69,
         "ionicons/dist/ionicons/svg/ios-water.svg":69,
         "ionicons/dist/ionicons/svg/ios-wifi.svg":68,
         "ionicons/dist/ionicons/svg/ios-wine.svg":68,
         "ionicons/dist/ionicons/svg/ios-woman.svg":69,
         "ionicons/dist/ionicons/svg/logo-android.svg":72,
         "ionicons/dist/ionicons/svg/logo-angular.svg":72,
         "ionicons/dist/ionicons/svg/logo-apple.svg":70,
         "ionicons/dist/ionicons/svg/logo-bitbucket.svg":74,
         "ionicons/dist/ionicons/svg/logo-bitcoin.svg":72,
         "ionicons/dist/ionicons/svg/logo-buffer.svg":71,
         "ionicons/dist/ionicons/svg/logo-chrome.svg":71,
         "ionicons/dist/ionicons/svg/logo-closed-captioning.svg":82,
         "ionicons/dist/ionicons/svg/logo-codepen.svg":72,
         "ionicons/dist/ionicons/svg/logo-css3.svg":69,
         "ionicons/dist/ionicons/svg/logo-designernews.svg":77,
         "ionicons/dist/ionicons/svg/logo-dribbble.svg":73,
         "ionicons/dist/ionicons/svg/logo-dropbox.svg":72,
         "ionicons/dist/ionicons/svg/logo-euro.svg":69,
         "ionicons/dist/ionicons/svg/logo-facebook.svg":73,
         "ionicons/dist/ionicons/svg/logo-flickr.svg":71,
         "ionicons/dist/ionicons/svg/logo-foursquare.svg":75,
         "ionicons/dist/ionicons/svg/logo-freebsd-devil.svg":78,
         "ionicons/dist/ionicons/svg/logo-game-controller-a.svg":82,
         "ionicons/dist/ionicons/svg/logo-game-controller-b.svg":82,
         "ionicons/dist/ionicons/svg/logo-github.svg":71,
         "ionicons/dist/ionicons/svg/logo-google.svg":71,
         "ionicons/dist/ionicons/svg/logo-googleplus.svg":75,
         "ionicons/dist/ionicons/svg/logo-hackernews.svg":75,
         "ionicons/dist/ionicons/svg/logo-html5.svg":70,
         "ionicons/dist/ionicons/svg/logo-instagram.svg":74,
         "ionicons/dist/ionicons/svg/logo-ionic.svg":70,
         "ionicons/dist/ionicons/svg/logo-ionitron.svg":73,
         "ionicons/dist/ionicons/svg/logo-javascript.svg":75,
         "ionicons/dist/ionicons/svg/logo-linkedin.svg":73,
         "ionicons/dist/ionicons/svg/logo-markdown.svg":73,
         "ionicons/dist/ionicons/svg/logo-model-s.svg":72,
         "ionicons/dist/ionicons/svg/logo-no-smoking.svg":75,
         "ionicons/dist/ionicons/svg/logo-nodejs.svg":71,
         "ionicons/dist/ionicons/svg/logo-npm.svg":68,
         "ionicons/dist/ionicons/svg/logo-octocat.svg":72,
         "ionicons/dist/ionicons/svg/logo-pinterest.svg":74,
         "ionicons/dist/ionicons/svg/logo-playstation.svg":76,
         "ionicons/dist/ionicons/svg/logo-polymer.svg":72,
         "ionicons/dist/ionicons/svg/logo-python.svg":71,
         "ionicons/dist/ionicons/svg/logo-reddit.svg":71,
         "ionicons/dist/ionicons/svg/logo-rss.svg":68,
         "ionicons/dist/ionicons/svg/logo-sass.svg":69,
         "ionicons/dist/ionicons/svg/logo-skype.svg":70,
         "ionicons/dist/ionicons/svg/logo-slack.svg":70,
         "ionicons/dist/ionicons/svg/logo-snapchat.svg":73,
         "ionicons/dist/ionicons/svg/logo-steam.svg":70,
         "ionicons/dist/ionicons/svg/logo-tumblr.svg":71,
         "ionicons/dist/ionicons/svg/logo-tux.svg":68,
         "ionicons/dist/ionicons/svg/logo-twitch.svg":71,
         "ionicons/dist/ionicons/svg/logo-twitter.svg":72,
         "ionicons/dist/ionicons/svg/logo-usd.svg":68,
         "ionicons/dist/ionicons/svg/logo-vimeo.svg":70,
         "ionicons/dist/ionicons/svg/logo-vk.svg":67,
         "ionicons/dist/ionicons/svg/logo-whatsapp.svg":73,
         "ionicons/dist/ionicons/svg/logo-windows.svg":72,
         "ionicons/dist/ionicons/svg/logo-wordpress.svg":74,
         "ionicons/dist/ionicons/svg/logo-xbox.svg":69,
         "ionicons/dist/ionicons/svg/logo-xing.svg":69,
         "ionicons/dist/ionicons/svg/logo-yahoo.svg":70,
         "ionicons/dist/ionicons/svg/logo-yen.svg":68,
         "ionicons/dist/ionicons/svg/logo-youtube.svg":72,
         "ionicons/dist/ionicons/svg/md-add-circle-outline.svg":81,
         "ionicons/dist/ionicons/svg/md-add-circle.svg":73,
         "ionicons/dist/ionicons/svg/md-add.svg":66,
         "ionicons/dist/ionicons/svg/md-airplane.svg":71,
         "ionicons/dist/ionicons/svg/md-alarm.svg":68,
         "ionicons/dist/ionicons/svg/md-albums.svg":69,
         "ionicons/dist/ionicons/svg/md-alert.svg":68,
         "ionicons/dist/ionicons/svg/md-american-football.svg":80,
         "ionicons/dist/ionicons/svg/md-analytics.svg":72,
         "ionicons/dist/ionicons/svg/md-aperture.svg":71,
         "ionicons/dist/ionicons/svg/md-apps.svg":67,
         "ionicons/dist/ionicons/svg/md-appstore.svg":71,
         "ionicons/dist/ionicons/svg/md-archive.svg":70,
         "ionicons/dist/ionicons/svg/md-arrow-back.svg":73,
         "ionicons/dist/ionicons/svg/md-arrow-down.svg":73,
         "ionicons/dist/ionicons/svg/md-arrow-dropdown-circle.svg":84,
         "ionicons/dist/ionicons/svg/md-arrow-dropdown.svg":77,
         "ionicons/dist/ionicons/svg/md-arrow-dropleft-circle.svg":84,
         "ionicons/dist/ionicons/svg/md-arrow-dropleft.svg":77,
         "ionicons/dist/ionicons/svg/md-arrow-dropright-circle.svg":85,
         "ionicons/dist/ionicons/svg/md-arrow-dropright.svg":78,
         "ionicons/dist/ionicons/svg/md-arrow-dropup-circle.svg":82,
         "ionicons/dist/ionicons/svg/md-arrow-dropup.svg":75,
         "ionicons/dist/ionicons/svg/md-arrow-forward.svg":76,
         "ionicons/dist/ionicons/svg/md-arrow-round-back.svg":79,
         "ionicons/dist/ionicons/svg/md-arrow-round-down.svg":79,
         "ionicons/dist/ionicons/svg/md-arrow-round-forward.svg":82,
         "ionicons/dist/ionicons/svg/md-arrow-round-up.svg":77,
         "ionicons/dist/ionicons/svg/md-arrow-up.svg":71,
         "ionicons/dist/ionicons/svg/md-at.svg":65,
         "ionicons/dist/ionicons/svg/md-attach.svg":69,
         "ionicons/dist/ionicons/svg/md-backspace.svg":72,
         "ionicons/dist/ionicons/svg/md-barcode.svg":70,
         "ionicons/dist/ionicons/svg/md-baseball.svg":71,
         "ionicons/dist/ionicons/svg/md-basket.svg":69,
         "ionicons/dist/ionicons/svg/md-basketball.svg":73,
         "ionicons/dist/ionicons/svg/md-battery-charging.svg":79,
         "ionicons/dist/ionicons/svg/md-battery-dead.svg":75,
         "ionicons/dist/ionicons/svg/md-battery-full.svg":75,
         "ionicons/dist/ionicons/svg/md-beaker.svg":69,
         "ionicons/dist/ionicons/svg/md-bed.svg":66,
         "ionicons/dist/ionicons/svg/md-beer.svg":67,
         "ionicons/dist/ionicons/svg/md-bicycle.svg":70,
         "ionicons/dist/ionicons/svg/md-bluetooth.svg":72,
         "ionicons/dist/ionicons/svg/md-boat.svg":67,
         "ionicons/dist/ionicons/svg/md-body.svg":67,
         "ionicons/dist/ionicons/svg/md-bonfire.svg":70,
         "ionicons/dist/ionicons/svg/md-book.svg":67,
         "ionicons/dist/ionicons/svg/md-bookmark.svg":71,
         "ionicons/dist/ionicons/svg/md-bookmarks.svg":72,
         "ionicons/dist/ionicons/svg/md-bowtie.svg":69,
         "ionicons/dist/ionicons/svg/md-briefcase.svg":72,
         "ionicons/dist/ionicons/svg/md-browsers.svg":71,
         "ionicons/dist/ionicons/svg/md-brush.svg":68,
         "ionicons/dist/ionicons/svg/md-bug.svg":66,
         "ionicons/dist/ionicons/svg/md-build.svg":68,
         "ionicons/dist/ionicons/svg/md-bulb.svg":67,
         "ionicons/dist/ionicons/svg/md-bus.svg":66,
         "ionicons/dist/ionicons/svg/md-business.svg":71,
         "ionicons/dist/ionicons/svg/md-cafe.svg":67,
         "ionicons/dist/ionicons/svg/md-calculator.svg":73,
         "ionicons/dist/ionicons/svg/md-calendar.svg":71,
         "ionicons/dist/ionicons/svg/md-call.svg":67,
         "ionicons/dist/ionicons/svg/md-camera.svg":69,
         "ionicons/dist/ionicons/svg/md-car.svg":66,
         "ionicons/dist/ionicons/svg/md-card.svg":67,
         "ionicons/dist/ionicons/svg/md-cart.svg":67,
         "ionicons/dist/ionicons/svg/md-cash.svg":67,
         "ionicons/dist/ionicons/svg/md-cellular.svg":71,
         "ionicons/dist/ionicons/svg/md-chatboxes.svg":72,
         "ionicons/dist/ionicons/svg/md-chatbubbles.svg":74,
         "ionicons/dist/ionicons/svg/md-checkbox-outline.svg":79,
         "ionicons/dist/ionicons/svg/md-checkbox.svg":71,
         "ionicons/dist/ionicons/svg/md-checkmark-circle-outline.svg":87,
         "ionicons/dist/ionicons/svg/md-checkmark-circle.svg":79,
         "ionicons/dist/ionicons/svg/md-checkmark.svg":72,
         "ionicons/dist/ionicons/svg/md-clipboard.svg":72,
         "ionicons/dist/ionicons/svg/md-clock.svg":68,
         "ionicons/dist/ionicons/svg/md-close-circle-outline.svg":83,
         "ionicons/dist/ionicons/svg/md-close-circle.svg":75,
         "ionicons/dist/ionicons/svg/md-close.svg":68,
         "ionicons/dist/ionicons/svg/md-cloud-circle.svg":75,
         "ionicons/dist/ionicons/svg/md-cloud-done.svg":73,
         "ionicons/dist/ionicons/svg/md-cloud-download.svg":77,
         "ionicons/dist/ionicons/svg/md-cloud-outline.svg":76,
         "ionicons/dist/ionicons/svg/md-cloud-upload.svg":75,
         "ionicons/dist/ionicons/svg/md-cloud.svg":68,
         "ionicons/dist/ionicons/svg/md-cloudy-night.svg":75,
         "ionicons/dist/ionicons/svg/md-cloudy.svg":69,
         "ionicons/dist/ionicons/svg/md-code-download.svg":76,
         "ionicons/dist/ionicons/svg/md-code-working.svg":75,
         "ionicons/dist/ionicons/svg/md-code.svg":67,
         "ionicons/dist/ionicons/svg/md-cog.svg":66,
         "ionicons/dist/ionicons/svg/md-color-fill.svg":73,
         "ionicons/dist/ionicons/svg/md-color-filter.svg":75,
         "ionicons/dist/ionicons/svg/md-color-palette.svg":76,
         "ionicons/dist/ionicons/svg/md-color-wand.svg":73,
         "ionicons/dist/ionicons/svg/md-compass.svg":70,
         "ionicons/dist/ionicons/svg/md-construct.svg":72,
         "ionicons/dist/ionicons/svg/md-contact.svg":70,
         "ionicons/dist/ionicons/svg/md-contacts.svg":71,
         "ionicons/dist/ionicons/svg/md-contract.svg":71,
         "ionicons/dist/ionicons/svg/md-contrast.svg":71,
         "ionicons/dist/ionicons/svg/md-copy.svg":67,
         "ionicons/dist/ionicons/svg/md-create.svg":69,
         "ionicons/dist/ionicons/svg/md-crop.svg":67,
         "ionicons/dist/ionicons/svg/md-cube.svg":67,
         "ionicons/dist/ionicons/svg/md-cut.svg":66,
         "ionicons/dist/ionicons/svg/md-desktop.svg":70,
         "ionicons/dist/ionicons/svg/md-disc.svg":67,
         "ionicons/dist/ionicons/svg/md-document.svg":71,
         "ionicons/dist/ionicons/svg/md-done-all.svg":71,
         "ionicons/dist/ionicons/svg/md-download.svg":71,
         "ionicons/dist/ionicons/svg/md-easel.svg":68,
         "ionicons/dist/ionicons/svg/md-egg.svg":66,
         "ionicons/dist/ionicons/svg/md-exit.svg":67,
         "ionicons/dist/ionicons/svg/md-expand.svg":69,
         "ionicons/dist/ionicons/svg/md-eye-off.svg":70,
         "ionicons/dist/ionicons/svg/md-eye.svg":66,
         "ionicons/dist/ionicons/svg/md-fastforward.svg":74,
         "ionicons/dist/ionicons/svg/md-female.svg":69,
         "ionicons/dist/ionicons/svg/md-filing.svg":69,
         "ionicons/dist/ionicons/svg/md-film.svg":67,
         "ionicons/dist/ionicons/svg/md-finger-print.svg":75,
         "ionicons/dist/ionicons/svg/md-fitness.svg":70,
         "ionicons/dist/ionicons/svg/md-flag.svg":67,
         "ionicons/dist/ionicons/svg/md-flame.svg":68,
         "ionicons/dist/ionicons/svg/md-flash-off.svg":72,
         "ionicons/dist/ionicons/svg/md-flash.svg":68,
         "ionicons/dist/ionicons/svg/md-flashlight.svg":73,
         "ionicons/dist/ionicons/svg/md-flask.svg":68,
         "ionicons/dist/ionicons/svg/md-flower.svg":69,
         "ionicons/dist/ionicons/svg/md-folder-open.svg":74,
         "ionicons/dist/ionicons/svg/md-folder.svg":69,
         "ionicons/dist/ionicons/svg/md-football.svg":71,
         "ionicons/dist/ionicons/svg/md-funnel.svg":69,
         "ionicons/dist/ionicons/svg/md-gift.svg":67,
         "ionicons/dist/ionicons/svg/md-git-branch.svg":73,
         "ionicons/dist/ionicons/svg/md-git-commit.svg":73,
         "ionicons/dist/ionicons/svg/md-git-compare.svg":74,
         "ionicons/dist/ionicons/svg/md-git-merge.svg":72,
         "ionicons/dist/ionicons/svg/md-git-network.svg":74,
         "ionicons/dist/ionicons/svg/md-git-pull-request.svg":79,
         "ionicons/dist/ionicons/svg/md-glasses.svg":70,
         "ionicons/dist/ionicons/svg/md-globe.svg":68,
         "ionicons/dist/ionicons/svg/md-grid.svg":67,
         "ionicons/dist/ionicons/svg/md-hammer.svg":69,
         "ionicons/dist/ionicons/svg/md-hand.svg":67,
         "ionicons/dist/ionicons/svg/md-happy.svg":68,
         "ionicons/dist/ionicons/svg/md-headset.svg":70,
         "ionicons/dist/ionicons/svg/md-heart-dislike.svg":76,
         "ionicons/dist/ionicons/svg/md-heart-empty.svg":74,
         "ionicons/dist/ionicons/svg/md-heart-half.svg":73,
         "ionicons/dist/ionicons/svg/md-heart.svg":68,
         "ionicons/dist/ionicons/svg/md-help-buoy.svg":72,
         "ionicons/dist/ionicons/svg/md-help-circle-outline.svg":82,
         "ionicons/dist/ionicons/svg/md-help-circle.svg":74,
         "ionicons/dist/ionicons/svg/md-help.svg":67,
         "ionicons/dist/ionicons/svg/md-home.svg":67,
         "ionicons/dist/ionicons/svg/md-hourglass.svg":72,
         "ionicons/dist/ionicons/svg/md-ice-cream.svg":72,
         "ionicons/dist/ionicons/svg/md-image.svg":68,
         "ionicons/dist/ionicons/svg/md-images.svg":69,
         "ionicons/dist/ionicons/svg/md-infinite.svg":71,
         "ionicons/dist/ionicons/svg/md-information-circle-outline.svg":89,
         "ionicons/dist/ionicons/svg/md-information-circle.svg":81,
         "ionicons/dist/ionicons/svg/md-information.svg":74,
         "ionicons/dist/ionicons/svg/md-jet.svg":66,
         "ionicons/dist/ionicons/svg/md-journal.svg":70,
         "ionicons/dist/ionicons/svg/md-key.svg":66,
         "ionicons/dist/ionicons/svg/md-keypad.svg":69,
         "ionicons/dist/ionicons/svg/md-laptop.svg":69,
         "ionicons/dist/ionicons/svg/md-leaf.svg":67,
         "ionicons/dist/ionicons/svg/md-link.svg":67,
         "ionicons/dist/ionicons/svg/md-list-box.svg":71,
         "ionicons/dist/ionicons/svg/md-list.svg":67,
         "ionicons/dist/ionicons/svg/md-locate.svg":69,
         "ionicons/dist/ionicons/svg/md-lock.svg":67,
         "ionicons/dist/ionicons/svg/md-log-in.svg":69,
         "ionicons/dist/ionicons/svg/md-log-out.svg":70,
         "ionicons/dist/ionicons/svg/md-magnet.svg":69,
         "ionicons/dist/ionicons/svg/md-mail-open.svg":72,
         "ionicons/dist/ionicons/svg/md-mail-unread.svg":74,
         "ionicons/dist/ionicons/svg/md-mail.svg":67,
         "ionicons/dist/ionicons/svg/md-male.svg":67,
         "ionicons/dist/ionicons/svg/md-man.svg":66,
         "ionicons/dist/ionicons/svg/md-map.svg":66,
         "ionicons/dist/ionicons/svg/md-medal.svg":68,
         "ionicons/dist/ionicons/svg/md-medical.svg":70,
         "ionicons/dist/ionicons/svg/md-medkit.svg":69,
         "ionicons/dist/ionicons/svg/md-megaphone.svg":72,
         "ionicons/dist/ionicons/svg/md-menu.svg":67,
         "ionicons/dist/ionicons/svg/md-mic-off.svg":70,
         "ionicons/dist/ionicons/svg/md-mic.svg":66,
         "ionicons/dist/ionicons/svg/md-microphone.svg":73,
         "ionicons/dist/ionicons/svg/md-moon.svg":67,
         "ionicons/dist/ionicons/svg/md-more.svg":67,
         "ionicons/dist/ionicons/svg/md-move.svg":67,
         "ionicons/dist/ionicons/svg/md-musical-note.svg":75,
         "ionicons/dist/ionicons/svg/md-musical-notes.svg":76,
         "ionicons/dist/ionicons/svg/md-navigate.svg":71,
         "ionicons/dist/ionicons/svg/md-notifications-off.svg":80,
         "ionicons/dist/ionicons/svg/md-notifications-outline.svg":84,
         "ionicons/dist/ionicons/svg/md-notifications.svg":76,
         "ionicons/dist/ionicons/svg/md-nuclear.svg":70,
         "ionicons/dist/ionicons/svg/md-nutrition.svg":72,
         "ionicons/dist/ionicons/svg/md-open.svg":67,
         "ionicons/dist/ionicons/svg/md-options.svg":70,
         "ionicons/dist/ionicons/svg/md-outlet.svg":69,
         "ionicons/dist/ionicons/svg/md-paper-plane.svg":74,
         "ionicons/dist/ionicons/svg/md-paper.svg":68,
         "ionicons/dist/ionicons/svg/md-partly-sunny.svg":75,
         "ionicons/dist/ionicons/svg/md-pause.svg":68,
         "ionicons/dist/ionicons/svg/md-paw.svg":66,
         "ionicons/dist/ionicons/svg/md-people.svg":69,
         "ionicons/dist/ionicons/svg/md-person-add.svg":73,
         "ionicons/dist/ionicons/svg/md-person.svg":69,
         "ionicons/dist/ionicons/svg/md-phone-landscape.svg":78,
         "ionicons/dist/ionicons/svg/md-phone-portrait.svg":77,
         "ionicons/dist/ionicons/svg/md-photos.svg":69,
         "ionicons/dist/ionicons/svg/md-pie.svg":66,
         "ionicons/dist/ionicons/svg/md-pin.svg":66,
         "ionicons/dist/ionicons/svg/md-pint.svg":67,
         "ionicons/dist/ionicons/svg/md-pizza.svg":68,
         "ionicons/dist/ionicons/svg/md-planet.svg":69,
         "ionicons/dist/ionicons/svg/md-play-circle.svg":74,
         "ionicons/dist/ionicons/svg/md-play.svg":67,
         "ionicons/dist/ionicons/svg/md-podium.svg":69,
         "ionicons/dist/ionicons/svg/md-power.svg":68,
         "ionicons/dist/ionicons/svg/md-pricetag.svg":71,
         "ionicons/dist/ionicons/svg/md-pricetags.svg":72,
         "ionicons/dist/ionicons/svg/md-print.svg":68,
         "ionicons/dist/ionicons/svg/md-pulse.svg":68,
         "ionicons/dist/ionicons/svg/md-qr-scanner.svg":73,
         "ionicons/dist/ionicons/svg/md-quote.svg":68,
         "ionicons/dist/ionicons/svg/md-radio-button-off.svg":79,
         "ionicons/dist/ionicons/svg/md-radio-button-on.svg":78,
         "ionicons/dist/ionicons/svg/md-radio.svg":68,
         "ionicons/dist/ionicons/svg/md-rainy.svg":68,
         "ionicons/dist/ionicons/svg/md-recording.svg":72,
         "ionicons/dist/ionicons/svg/md-redo.svg":67,
         "ionicons/dist/ionicons/svg/md-refresh-circle.svg":77,
         "ionicons/dist/ionicons/svg/md-refresh.svg":70,
         "ionicons/dist/ionicons/svg/md-remove-circle-outline.svg":84,
         "ionicons/dist/ionicons/svg/md-remove-circle.svg":76,
         "ionicons/dist/ionicons/svg/md-remove.svg":69,
         "ionicons/dist/ionicons/svg/md-reorder.svg":70,
         "ionicons/dist/ionicons/svg/md-repeat.svg":69,
         "ionicons/dist/ionicons/svg/md-resize.svg":69,
         "ionicons/dist/ionicons/svg/md-restaurant.svg":73,
         "ionicons/dist/ionicons/svg/md-return-left.svg":74,
         "ionicons/dist/ionicons/svg/md-return-right.svg":75,
         "ionicons/dist/ionicons/svg/md-reverse-camera.svg":77,
         "ionicons/dist/ionicons/svg/md-rewind.svg":69,
         "ionicons/dist/ionicons/svg/md-ribbon.svg":69,
         "ionicons/dist/ionicons/svg/md-rocket.svg":69,
         "ionicons/dist/ionicons/svg/md-rose.svg":67,
         "ionicons/dist/ionicons/svg/md-sad.svg":66,
         "ionicons/dist/ionicons/svg/md-save.svg":67,
         "ionicons/dist/ionicons/svg/md-school.svg":69,
         "ionicons/dist/ionicons/svg/md-search.svg":69,
         "ionicons/dist/ionicons/svg/md-send.svg":67,
         "ionicons/dist/ionicons/svg/md-settings.svg":71,
         "ionicons/dist/ionicons/svg/md-share-alt.svg":72,
         "ionicons/dist/ionicons/svg/md-share.svg":68,
         "ionicons/dist/ionicons/svg/md-shirt.svg":68,
         "ionicons/dist/ionicons/svg/md-shuffle.svg":70,
         "ionicons/dist/ionicons/svg/md-skip-backward.svg":76,
         "ionicons/dist/ionicons/svg/md-skip-forward.svg":75,
         "ionicons/dist/ionicons/svg/md-snow.svg":67,
         "ionicons/dist/ionicons/svg/md-speedometer.svg":74,
         "ionicons/dist/ionicons/svg/md-square-outline.svg":77,
         "ionicons/dist/ionicons/svg/md-square.svg":69,
         "ionicons/dist/ionicons/svg/md-star-half.svg":72,
         "ionicons/dist/ionicons/svg/md-star-outline.svg":75,
         "ionicons/dist/ionicons/svg/md-star.svg":67,
         "ionicons/dist/ionicons/svg/md-stats.svg":68,
         "ionicons/dist/ionicons/svg/md-stopwatch.svg":72,
         "ionicons/dist/ionicons/svg/md-subway.svg":69,
         "ionicons/dist/ionicons/svg/md-sunny.svg":68,
         "ionicons/dist/ionicons/svg/md-swap.svg":67,
         "ionicons/dist/ionicons/svg/md-switch.svg":69,
         "ionicons/dist/ionicons/svg/md-sync.svg":67,
         "ionicons/dist/ionicons/svg/md-tablet-landscape.svg":79,
         "ionicons/dist/ionicons/svg/md-tablet-portrait.svg":78,
         "ionicons/dist/ionicons/svg/md-tennisball.svg":73,
         "ionicons/dist/ionicons/svg/md-text.svg":67,
         "ionicons/dist/ionicons/svg/md-thermometer.svg":74,
         "ionicons/dist/ionicons/svg/md-thumbs-down.svg":74,
         "ionicons/dist/ionicons/svg/md-thumbs-up.svg":72,
         "ionicons/dist/ionicons/svg/md-thunderstorm.svg":75,
         "ionicons/dist/ionicons/svg/md-time.svg":67,
         "ionicons/dist/ionicons/svg/md-timer.svg":68,
         "ionicons/dist/ionicons/svg/md-today.svg":68,
         "ionicons/dist/ionicons/svg/md-train.svg":68,
         "ionicons/dist/ionicons/svg/md-transgender.svg":74,
         "ionicons/dist/ionicons/svg/md-trash.svg":68,
         "ionicons/dist/ionicons/svg/md-trending-down.svg":76,
         "ionicons/dist/ionicons/svg/md-trending-up.svg":74,
         "ionicons/dist/ionicons/svg/md-trophy.svg":69,
         "ionicons/dist/ionicons/svg/md-tv.svg":65,
         "ionicons/dist/ionicons/svg/md-umbrella.svg":71,
         "ionicons/dist/ionicons/svg/md-undo.svg":67,
         "ionicons/dist/ionicons/svg/md-unlock.svg":69,
         "ionicons/dist/ionicons/svg/md-videocam.svg":71,
         "ionicons/dist/ionicons/svg/md-volume-high.svg":74,
         "ionicons/dist/ionicons/svg/md-volume-low.svg":73,
         "ionicons/dist/ionicons/svg/md-volume-mute.svg":74,
         "ionicons/dist/ionicons/svg/md-volume-off.svg":73,
         "ionicons/dist/ionicons/svg/md-walk.svg":67,
         "ionicons/dist/ionicons/svg/md-wallet.svg":69,
         "ionicons/dist/ionicons/svg/md-warning.svg":70,
         "ionicons/dist/ionicons/svg/md-watch.svg":68,
         "ionicons/dist/ionicons/svg/md-water.svg":68,
         "ionicons/dist/ionicons/svg/md-wifi.svg":67,
         "ionicons/dist/ionicons/svg/md-wine.svg":67,
         "ionicons/dist/ionicons/svg/md-woman.svg":81,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/toConsumableArray.js":83,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js":102,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/iterableToArray.js":123,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js":82,
         "path-to-regexp/index.js":3165,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/objectSpread.js":410,
         "@ionic/core/dist/esm/es5/ionic.core.js":28492,
         "ionicons/dist/esm/es5/build/chunk-1ca7e569.js":14648,
         "ionicons/dist/ionicons/svg/index.esm.js":13674,
         "@ionic/core/dist/esm/es5/ionic.components.js":24319,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/classCallCheck.js":95,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/createClass.js":227,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/typeof.js":459,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/possibleConstructorReturn.js":73,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js":121,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/getPrototypeOf.js":131,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js":94,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/inherits.js":274,
         "@ionic/react/dist/components/utils/index.js":1033,
         "@ionic/react/dist/components/createComponent.js":1016,
         "@ionic/react/dist/components/createControllerComponent.js":1700,
         "@ionic/react/dist/components/IonAlert.js":43,
         "@ionic/react/dist/components/IonLoading.js":43,
         "@ionic/react/dist/components/IonToast.js":39,
         "@ionic/react/dist/components/createOverlayComponent.js":1845,
         "@ionic/react/dist/components/IonActionSheet.js":57,
         "@ionic/react/dist/components/IonModal.js":39,
         "@ionic/react/dist/components/IonPopover.js":43,
         "@ionic/react/dist/components/IonPage.js":643,
         "@ionic/core/dist/esm/es5/ionic.define.js":32,
         "@ionic/react/dist/components/navigation/IonTabBar.js":1310,
         "@ionic/react/dist/components/navigation/IonRouterOutlet.js":3176,
         "@ionic/react/dist/components/index.js":1524,
         "@ionic/react/dist/index.js":295,
         "object-assign/index.js":946,
         "react-is/index.js":47,
         "babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js":363,
         "react-router-last-location/dist/index.js":3600,
         "@ionic/core/dist/esm/es5/ionic.global.js":3085,
         "create-react-context/lib/index.js":188,
         "hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js":979,
         "lodash-es/_freeGlobal.js":118,
         "react/cjs/react.production.min.js":6490,
         "react-dom/cjs/react-dom.production.min.js":106133,
         "scheduler/index.js":48,
         "scheduler/cjs/scheduler.production.min.js":4643,
         "regenerator-runtime/runtime-module.js":366,
         "regenerator-runtime/runtime.js":6334,
         "create-react-context/lib/implementation.js":2686,
         "prop-types/factoryWithThrowingShims.js":652,
         "prop-types/lib/ReactPropTypesSecret.js":88,
         "gud/index.js":136,
         "fbjs/lib/warning.js":55,
         "fbjs/lib/emptyFunction.js":265,
         "path-to-regexp/node_modules/isarray/index.js":126,
         "react-is/cjs/react-is.production.min.js":1900,
         "<unmapped>":132
      }
   },
   {
      "bundle":"159.07b8221e.chunk.js",
      "totalBytes":8807,
      "unmappedBytes":138,
      "files":{
         "build/tg1vwd7z.entry.js":6514,
         "polyfills/tslib.js":1763,
         "build/chunk-81780b86.js":392,
         "<unmapped>":138
      }
   },
   {
      "bundle":"16.51d23b1b.chunk.js",
      "totalBytes":697764,
      "unmappedBytes":177,
      "files":{
         "@amcharts/amcharts4/.internal/core/elements/PopupCSS.js":1384,
         "@amcharts/amcharts4/.internal/core/elements/Popup.js":11336,
         "@amcharts/amcharts4/.internal/core/defs/SVGDefaults.js":275,
         "@amcharts/amcharts4/.internal/core/rendering/Group.js":967,
         "@amcharts/amcharts4/.internal/core/interaction/InteractionObject.js":7538,
         "@amcharts/amcharts4/.internal/core/interaction/InteractionKeyboardObject.js":1062,
         "@amcharts/amcharts4/.internal/core/interaction/Inertia.js":1125,
         "@amcharts/amcharts4/.internal/core/utils/Time.js":115,
         "@amcharts/amcharts4/.internal/core/formatters/NumberFormatter.js":7610,
         "@amcharts/amcharts4/.internal/core/export/Export.js":36404,
         "@amcharts/amcharts4/.internal/core/data/DataSource.js":4848,
         "@amcharts/amcharts4/.internal/core/elements/Line.js":1747,
         "@amcharts/amcharts4/.internal/core/elements/PointedRectangle.js":1579,
         "@amcharts/amcharts4/.internal/core/elements/PointedShape.js":1233,
         "@amcharts/amcharts4/.internal/core/elements/Polyarc.js":1441,
         "@amcharts/amcharts4/.internal/core/elements/Polygon.js":2376,
         "@amcharts/amcharts4/.internal/core/utils/Morpher.js":5083,
         "@amcharts/amcharts4/.internal/core/rendering/filters/DropShadowFilter.js":2153,
         "@amcharts/amcharts4/.internal/core/utils/ColorSet.js":3276,
         "@amcharts/amcharts4/.internal/core/export/ExportCSS.js":2447,
         "@amcharts/amcharts4/.internal/core/export/ExportMenu.js":11427,
         "@amcharts/amcharts4/.internal/core/utils/Net.js":826,
         "css-element-queries/src/ResizeSensor.js":3495,
         "polylabel/index.js":1575,
         "tinyqueue/index.js":1540,
         "@amcharts/amcharts4/.internal/charts/Legend.js":7822,
         "@amcharts/amcharts4/.internal/charts/axes/AxisBreak.js":3413,
         "@amcharts/amcharts4/.internal/charts/axes/Axis.js":15698,
         "@amcharts/amcharts4/.internal/charts/axes/AxisLine.js":314,
         "@amcharts/amcharts4/.internal/charts/axes/AxisFill.js":1283,
         "@amcharts/amcharts4/.internal/charts/axes/Grid.js":778,
         "@amcharts/amcharts4/.internal/charts/axes/AxisLabel.js":723,
         "@amcharts/amcharts4/.internal/charts/elements/Tick.js":477,
         "@amcharts/amcharts4/.internal/charts/axes/AxisTick.js":773,
         "@amcharts/amcharts4/.internal/charts/axes/AxisRenderer.js":7904,
         "@amcharts/amcharts4/.internal/charts/axes/AxisRendererY.js":4392,
         "@amcharts/amcharts4/.internal/charts/axes/ValueAxisBreak.js":519,
         "@amcharts/amcharts4/.internal/charts/axes/ValueAxis.js":16656,
         "@amcharts/amcharts4/.internal/charts/axes/AxisRendererX.js":4214,
         "@amcharts/amcharts4/.internal/charts/elements/HeatLegend.js":6010,
         "@amcharts/amcharts4/.internal/charts/Chart.js":3737,
         "@amcharts/amcharts4/.internal/charts/elements/Bullet.js":1597,
         "@amcharts/amcharts4/.internal/charts/series/Series.js":12411,
         "@amcharts/amcharts4/.internal/charts/types/SerialChart.js":2270,
         "d3-geo/src/adder.js":317,
         "d3-geo/src/math.js":410,
         "d3-geo/src/noop.js":15,
         "d3-geo/src/stream.js":1050,
         "d3-geo/src/area.js":568,
         "d3-geo/src/cartesian.js":431,
         "d3-geo/src/bounds.js":1772,
         "d3-geo/src/centroid.js":4,
         "d3-geo/src/compose.js":163,
         "d3-geo/src/rotation.js":770,
         "d3-geo/src/circle.js":301,
         "d3-geo/src/clip/buffer.js":228,
         "d3-geo/src/pointEqual.js":60,
         "d3-geo/src/clip/rejoin.js":924,
         "d3-geo/src/polygonContains.js":566,
         "d3-array/src/ascending.js":49,
         "d3-array/src/bisect.js":29,
         "d3-array/src/bisector.js":315,
         "d3-array/src/cross.js":4,
         "d3-array/src/array.js":35,
         "d3-array/src/range.js":168,
         "d3-array/src/ticks.js":41,
         "d3-array/src/threshold/sturges.js":4,
         "d3-array/src/merge.js":150,
         "d3-array/src/zip.js":4,
         "d3-geo/src/clip/index.js":1190,
         "d3-geo/src/clip/antimeridian.js":919,
         "d3-geo/src/clip/circle.js":1444,
         "d3-geo/src/clip/line.js":528,
         "d3-geo/src/clip/rectangle.js":1619,
         "d3-geo/src/clip/extent.js":4,
         "d3-geo/src/length.js":409,
         "d3-geo/src/distance.js":96,
         "d3-geo/src/graticule.js":1646,
         "d3-geo/src/interpolate.js":346,
         "d3-geo/src/path/area.js":406,
         "d3-geo/src/identity.js":25,
         "d3-geo/src/path/bounds.js":233,
         "d3-geo/src/path/centroid.js":821,
         "d3-geo/src/path/context.js":532,
         "d3-geo/src/path/measure.js":350,
         "d3-geo/src/path/string.js":800,
         "d3-geo/src/transform.js":410,
         "d3-geo/src/projection/fit.js":771,
         "d3-geo/src/projection/resample.js":1103,
         "d3-geo/src/projection/index.js":2085,
         "d3-geo/src/projection/conic.js":140,
         "d3-geo/src/projection/conicEqualArea.js":330,
         "d3-geo/src/projection/cylindricalEqualArea.js":113,
         "d3-geo/src/projection/albers.js":117,
         "d3-geo/src/projection/albersUsa.js":1811,
         "d3-geo/src/projection/azimuthal.js":203,
         "d3-geo/src/projection/azimuthalEqualArea.js":153,
         "d3-geo/src/projection/azimuthalEquidistant.js":81,
         "d3-geo/src/projection/mercator.js":792,
         "d3-geo/src/projection/equirectangular.js":89,
         "d3-geo/src/projection/conicEquidistant.js":4,
         "d3-geo/src/projection/equalEarth.js":437,
         "d3-geo/src/projection/gnomonic.js":82,
         "d3-geo/src/projection/naturalEarth1.js":484,
         "d3-geo/src/projection/orthographic.js":123,
         "d3-geo/src/projection/stereographic.js":168,
         "d3-geo/src/projection/transverseMercator.js":100,
         "@amcharts/amcharts4/.internal/charts/map/MapSeries.js":5706,
         "@amcharts/amcharts4/.internal/charts/map/MapObject.js":1442,
         "@amcharts/amcharts4/.internal/charts/map/MapImage.js":1108,
         "@amcharts/amcharts4/.internal/charts/map/MapUtils.js":952,
         "@amcharts/amcharts4/.internal/charts/map/MapPolygon.js":3537,
         "@amcharts/amcharts4/.internal/charts/map/MapPolygonSeries.js":3880,
         "@amcharts/amcharts4/.internal/charts/map/projections/Projection.js":2735,
         "d3-geo/src/path/index.js":714,
         "@amcharts/amcharts4/.internal/charts/map/SmallMap.js":3099,
         "@amcharts/amcharts4/.internal/charts/map/Geo.js":595,
         "@amcharts/amcharts4/.internal/charts/map/MapLineObject.js":1130,
         "@amcharts/amcharts4/.internal/charts/map/MapImageSeries.js":3585,
         "@amcharts/amcharts4/.internal/charts/map/MapLine.js":4837,
         "@amcharts/amcharts4/.internal/charts/map/MapLineSeries.js":3588,
         "@amcharts/amcharts4/.internal/charts/map/Graticule.js":185,
         "@amcharts/amcharts4/.internal/charts/map/GraticuleSeries.js":2083,
         "@amcharts/amcharts4/.internal/charts/types/MapChart.js":16934,
         "@amcharts/amcharts4/.internal/charts/map/MapSpline.js":401,
         "@amcharts/amcharts4/.internal/charts/map/MapArc.js":336,
         "@amcharts/amcharts4/.internal/charts/map/MapSplineSeries.js":464,
         "@amcharts/amcharts4/.internal/charts/map/MapArcSeries.js":466,
         "@amcharts/amcharts4/.internal/charts/map/ZoomControl.js":4365,
         "@amcharts/amcharts4/.internal/charts/map/projections/Mercator.js":143,
         "d3-geo-projection/src/math.js":680,
         "d3-geo-projection/src/aitoff.js":470,
         "d3-geo-projection/src/august.js":362,
         "d3-geo-projection/src/baker.js":351,
         "d3-geo-projection/src/hammer.js":117,
         "d3-geo-projection/src/mollweide.js":278,
         "d3-geo-projection/src/boggs.js":307,
         "d3-geo-projection/src/sinusoidal.js":78,
         "d3-geo-projection/src/bromley.js":14,
         "d3-geo-projection/src/collignon.js":140,
         "d3-geo-projection/src/craig.js":4,
         "d3-geo-projection/src/craster.js":155,
         "d3-geo-projection/src/cylindricalEqualArea.js":116,
         "d3-geo-projection/src/eckert1.js":144,
         "d3-geo-projection/src/eckert2.js":182,
         "d3-geo-projection/src/eckert3.js":174,
         "d3-geo-projection/src/eckert4.js":306,
         "d3-geo-projection/src/eckert5.js":131,
         "d3-geo-projection/src/eckert6.js":273,
         "d3-geo-projection/src/eisenlohr.js":913,
         "d3-geo-projection/src/fahey.js":152,
         "d3-geo-projection/src/foucaut.js":152,
         "d3-geo-projection/src/newton.js":158,
         "d3-geo-projection/src/gingery.js":4,
         "d3-geo-projection/src/ginzburgPolyconic.js":693,
         "d3-geo-projection/src/ginzburg4.js":58,
         "d3-geo-projection/src/ginzburg5.js":65,
         "d3-geo-projection/src/ginzburg6.js":50,
         "d3-geo-projection/src/ginzburg8.js":317,
         "d3-geo-projection/src/ginzburg9.js":59,
         "d3-geo-projection/src/gringorten.js":1478,
         "d3-geo-projection/src/elliptic.js":1222,
         "d3-geo-projection/src/guyou.js":555,
         "d3-geo-projection/src/healpix.js":6,
         "d3-geo-projection/src/hill.js":4,
         "d3-geo-projection/src/sinuMollweide.js":171,
         "d3-geo-projection/src/homolosine.js":156,
         "d3-geo-projection/src/kavrayskiy7.js":108,
         "d3-geo-projection/src/lagrange.js":4,
         "d3-geo-projection/src/larrivee.js":436,
         "d3-geo-projection/src/laskowski.js":652,
         "d3-geo-projection/src/littrow.js":163,
         "d3-geo-projection/src/miller.js":156,
         "d3-geo-projection/src/mtFlatPolarParabolic.js":204,
         "d3-geo-projection/src/mtFlatPolarQuartic.js":297,
         "d3-geo-projection/src/mtFlatPolarSinusoidal.js":292,
         "d3-geo-projection/src/naturalEarth2.js":416,
         "d3-geo-projection/src/nellHammer.js":192,
         "d3-geo-projection/src/nicolosi.js":509,
         "d3-geo-projection/src/patterson.js":336,
         "d3-geo-projection/src/polyconic.js":345,
         "d3-geo-projection/src/polyhedral/octahedron.js":177,
         "d3-geo-projection/src/polyhedral/collignon.js":115,
         "d3-geo-projection/src/rectangularPolyconic.js":4,
         "d3-geo-projection/src/robinson.js":1018,
         "d3-geo-projection/src/times.js":172,
         "d3-geo-projection/src/vanDerGrinten.js":613,
         "d3-geo-projection/src/vanDerGrinten2.js":414,
         "d3-geo-projection/src/vanDerGrinten3.js":319,
         "d3-geo-projection/src/vanDerGrinten4.js":815,
         "d3-geo-projection/src/wagner.js":4,
         "d3-geo-projection/src/wagner4.js":63,
         "d3-geo-projection/src/wagner6.js":106,
         "d3-geo-projection/src/wagner7.js":254,
         "d3-geo-projection/src/wiechel.js":249,
         "d3-geo-projection/src/winkel3.js":449,
         "@amcharts/amcharts4/.internal/charts/map/projections/Miller.js":137,
         "@amcharts/amcharts4/.internal/charts/map/projections/Eckert6.js":142,
         "@amcharts/amcharts4/.internal/charts/map/projections/Orthographic.js":147,
         "@amcharts/amcharts4/.internal/charts/map/projections/Stereographic.js":148,
         "@amcharts/amcharts4/.internal/charts/map/projections/Albers.js":141,
         "@amcharts/amcharts4/.internal/charts/map/projections/AlbersUsa.js":144,
         "@amcharts/amcharts4/.internal/charts/map/projections/NaturalEarth1.js":148,
         "@amcharts/amcharts4/.internal/charts/map/projections/AzimuthalEqualArea.js":153,
         "@amcharts/amcharts4/.internal/charts/map/projections/EqualEarth.js":145,
         "@amcharts/amcharts4/maps.js":331,
         "@amcharts/amcharts4/.internal/core/elements/Ellipse.js":676,
         "@amcharts/amcharts4/.internal/core/elements/Image.js":1379,
         "@amcharts/amcharts4/.internal/core/elements/Slice.js":3961,
         "@amcharts/amcharts4/.internal/core/elements/Preloader.js":2101,
         "@amcharts/amcharts4/.internal/core/elements/ResizeButton.js":814,
         "@amcharts/amcharts4/.internal/core/elements/Scrollbar.js":11728,
         "@amcharts/amcharts4/.internal/core/elements/Slider.js":762,
         "@amcharts/amcharts4/.internal/core/elements/TextLink.js":447,
         "@amcharts/amcharts4/.internal/core/elements/Trapezoid.js":2194,
         "@amcharts/amcharts4/.internal/core/elements/WavedCircle.js":1867,
         "@amcharts/amcharts4/.internal/core/elements/ZoomOutButton.js":848,
         "@amcharts/amcharts4/.internal/core/elements/PlayButton.js":1182,
         "@amcharts/amcharts4/.internal/core/rendering/fills/ColorModifier.js":207,
         "@amcharts/amcharts4/.internal/core/rendering/fills/GradientModifier.js":1720,
         "@amcharts/amcharts4/.internal/core/rendering/fills/LinearGradientModifier.js":322,
         "@amcharts/amcharts4/.internal/core/elements/3d/Cone.js":2079,
         "@amcharts/amcharts4/.internal/core/rendering/filters/LightenFilter.js":573,
         "@amcharts/amcharts4/.internal/core/elements/3d/Rectangle3D.js":2173,
         "@amcharts/amcharts4/.internal/core/elements/3d/Slice3D.js":3141,
         "@amcharts/amcharts4/.internal/core/rendering/fills/RadialGradientModifier.js":315,
         "@amcharts/amcharts4/.internal/core/rendering/fills/LinePattern.js":275,
         "@amcharts/amcharts4/.internal/core/rendering/fills/RectPattern.js":754,
         "@amcharts/amcharts4/.internal/core/rendering/filters/ColorizeFilter.js":936,
         "@amcharts/amcharts4/.internal/core/rendering/filters/DesaturateFilter.js":579,
         "@amcharts/amcharts4/.internal/core/rendering/filters/BlurFilter.js":560,
         "@amcharts/amcharts4/.internal/core/rendering/filters/FocusFilter.js":1913,
         "@amcharts/amcharts4/.internal/core/utils/Plugin.js":348,
         "@amcharts/amcharts4/.internal/core/elements/AmChartsLogo.js":1227,
         "@amcharts/amcharts4/.internal/core/utils/Instance.js":1930,
         "@amcharts/amcharts4/core.js":136,
         "tslib/tslib.es6.js":2400,
         "@amcharts/amcharts4/.internal/core/Registry.js":2628,
         "@amcharts/amcharts4/.internal/core/utils/Type.js":1380,
         "@amcharts/amcharts4/.internal/core/utils/Math.js":3548,
         "@amcharts/amcharts4/.internal/core/utils/Disposer.js":1136,
         "@amcharts/amcharts4/.internal/core/utils/Array.js":1904,
         "@amcharts/amcharts4/.internal/core/utils/List.js":8102,
         "@amcharts/amcharts4/.internal/core/utils/Utils.js":7492,
         "@amcharts/amcharts4/.internal/core/utils/Iterator.js":2084,
         "@amcharts/amcharts4/.internal/core/Container.js":17437,
         "@amcharts/amcharts4/.internal/core/utils/Percent.js":536,
         "@amcharts/amcharts4/.internal/core/Base.js":7464,
         "@amcharts/amcharts4/.internal/core/utils/InterfaceColorSet.js":1324,
         "@amcharts/amcharts4/.internal/core/Sprite.js":80218,
         "@amcharts/amcharts4/.internal/core/utils/Color.js":2055,
         "@amcharts/amcharts4/.internal/core/utils/DOM.js":3746,
         "@amcharts/amcharts4/.internal/core/utils/Object.js":912,
         "@amcharts/amcharts4/.internal/core/rendering/Path.js":2593,
         "@amcharts/amcharts4/.internal/core/utils/Dictionary.js":3797,
         "@amcharts/amcharts4/.internal/core/utils/Adapter.js":1838,
         "@amcharts/amcharts4/.internal/core/utils/Strings.js":320,
         "@amcharts/amcharts4/.internal/core/utils/Animation.js":5196,
         "@amcharts/amcharts4/.internal/core/interaction/Interaction.js":27747,
         "@amcharts/amcharts4/.internal/core/utils/Responsive.js":4790,
         "@amcharts/amcharts4/.internal/core/utils/AsyncPending.js":782,
         "@amcharts/amcharts4/.internal/core/utils/Ease.js":357,
         "@amcharts/amcharts4/.internal/core/utils/EventDispatcher.js":4288,
         "@amcharts/amcharts4/.internal/core/utils/Keyboard.js":1000,
         "@amcharts/amcharts4/.internal/core/elements/Label.js":13706,
         "@amcharts/amcharts4/.internal/core/System.js":4556,
         "@amcharts/amcharts4/.internal/core/rendering/Paper.js":1316,
         "@amcharts/amcharts4/.internal/core/Options.js":222,
         "@amcharts/amcharts4/lang/en.js":4381,
         "@amcharts/amcharts4/.internal/core/utils/Language.js":1846,
         "@amcharts/amcharts4/.internal/core/utils/SortedList.js":4120,
         "@amcharts/amcharts4/.internal/core/formatters/TextFormatter.js":3439,
         "@amcharts/amcharts4/.internal/core/elements/RoundedRectangle.js":2224,
         "@amcharts/amcharts4/.internal/core/rendering/filters/Filter.js":2083,
         "@amcharts/amcharts4/.internal/core/utils/Colors.js":6867,
         "@amcharts/amcharts4/.internal/core/rendering/fills/LinearGradient.js":1899,
         "@amcharts/amcharts4/.internal/core/Component.js":16377,
         "@amcharts/amcharts4/.internal/core/DataItem.js":9303,
         "@amcharts/amcharts4/.internal/core/elements/Button.js":1820,
         "@amcharts/amcharts4/.internal/core/interaction/Mouse.js":645,
         "@amcharts/amcharts4/.internal/core/formatters/DateFormatter.js":12432,
         "@amcharts/amcharts4/.internal/core/rendering/Smoothing.js":1945,
         "@amcharts/amcharts4/.internal/core/utils/String.js":379,
         "@amcharts/amcharts4/.internal/core/utils/Cache.js":697,
         "@amcharts/amcharts4/.internal/core/rendering/AMElement.js":3186,
         "@amcharts/amcharts4/.internal/core/rendering/fills/Pattern.js":5413,
         "@amcharts/amcharts4/.internal/core/rendering/fills/RadialGradient.js":2288,
         "@amcharts/amcharts4/.internal/core/elements/Rectangle.js":769,
         "@amcharts/amcharts4/.internal/core/elements/Circle.js":1012,
         "@amcharts/amcharts4/.internal/core/elements/Polyline.js":1435,
         "@amcharts/amcharts4/.internal/core/elements/Tooltip.js":6154,
         "@amcharts/amcharts4/.internal/core/elements/WavedLine.js":1143,
         "@amcharts/amcharts4/.internal/core/SpriteState.js":1963,
         "@amcharts/amcharts4/.internal/core/utils/Number.js":106,
         "@amcharts/amcharts4/.internal/core/utils/Order.js":99,
         "@amcharts/amcharts4/.internal/core/SpriteEvents.js":2273,
         "@amcharts/amcharts4/.internal/core/rendering/SVGContainer.js":2908,
         "@amcharts/amcharts4/.internal/core/interaction/InteractionObjectEvents.js":1511,
         "@amcharts/amcharts4/.internal/core/elements/Modal.js":256,
         "@amcharts/amcharts4/.internal/core/formatters/DurationFormatter.js":6578,
         "@amcharts/amcharts4/.internal/core/utils/Validatable.js":456,
         "@amcharts/amcharts4/.internal/core/data/DataLoader.js":1565,
         "@amcharts/amcharts4/.internal/core/data/CSVParser.js":1719,
         "@amcharts/amcharts4/.internal/core/data/DataParser.js":1293,
         "@amcharts/amcharts4/.internal/core/data/JSONParser.js":719,
         "@amcharts/amcharts4/.internal/core/elements/Polyspline.js":1293,
         "@amcharts/amcharts4/.internal/core/elements/Triangle.js":923,
         "@amcharts/amcharts4/.internal/core/elements/WavedRectangle.js":1554,
         "<unmapped>":177
      }
   },
   {
      "bundle":"160.0d4bb1eb.chunk.js",
      "totalBytes":8838,
      "unmappedBytes":138,
      "files":{
         "build/tg1vwd7z.sc.entry.js":6545,
         "polyfills/tslib.js":1763,
         "build/chunk-81780b86.js":392,
         "<unmapped>":138
      }
   },
   "..."
]

  • We could find duplicate imports
  • We could detect known culprits (e.g. the entire lodash bundled, or moment.js bundled with other modules)
  • Large files in a bundle can be an issue too. We can recommend async-loading them (like we did with worldLight.js, a 200+ kb file)
  • Bundling many SVGs in a JS bundle? Why when we have h2? Even worse if it's a 100kB+ bundle.

The one thing we can figure out for CRA but I'm not sure how to detect in other environments without webpack stats is the entry point. I think the key factor is web perf is keeping the entry point (app core) light.

Size module checks sizes on already matched files

In a default CRA app, there are these two default thresholds:

    {
      path: './build/static/js/main.*.chunk.js',
      maxSize: '5 KB',
    },
    {
      path: './build/static/js/*.chunk.js',
      maxSize: '150 KB',
    },

The first one is meant to match the /build/static/js/main.28647029.chunk.js file but since each threshold checks matches, both of the thresholds are checking that one file.

Screen_Shot_2019-05-16_at_2_15_21_PM

I would expect the first threshold to match the file and the second threshold to disregard it.

There are two ways to fix this:

  1. Keep an array of checked files and when iterating over the files check this array to see if it has already been checked. If it has, disregard it. If it hasn't, check it and add it to the array.
  2. Gather all the paths into an array and get all files matching them. Then, iterate over the matched files, find the first path that matches and use it to check. I think for performance, this is more desirable since it would only be going to the file system once instead of once per threshold.

Modules

Actionable things should be defined as different modules. For example, a directory size measuring is one module, running lighthouse is another module.

We may also find that a module may depend on another module so there may be a dependency tree that may need to be implemented.

We also need a way for modules to be user defined in case a custom module is needed and can be defined via a node module or a path on the filesystem.

Docs

We can write docs anytime but we need to track what docs need to be done. These are in the form of markdown files in the docs directory. Some docs may be written but they are not audited for completeness, docs can always be more descriptive with examples.

  • ci
    • circleci
    • travisci
  • command
    • cra
    • heap-snapshot
    • lighthouse
    • size
    • unused-source
  • config
  • event
  • module
    • chrome
    • heap-snapshot
    • lighthouse
    • serve
    • size
    • unused-source
  • output
    • html
    • json
    • markdown
  • utils
  • vcs
    • github

Read jobs from config file

The process should pick up jobs listed in the cwd config file if no jobs are passed explicitly in the CLI

Access to Modus NPM repo

The team needs to get access to the modus npm repo so that we can start testing publishing and installing (with modir maybe).

Plugins

Plugins differ from modules in that plugins allow to hook into the executions of modules and the core system. We could use hooks to accomplish this (like is used for serverless framework's plugin system).

Like modules, we need to allow plugins to be project defined via node module and path on filesystem.

SQLite plugin needs to create directory

The sqlite3 module does not handle creating the directories to save the database file to. So if you pass in a file with a nested and nonexistent directory path like:

plugins:
  - "@modus/gimbal-plugin-last-value"
  - plugin: "@modus/gimbal-plugin-sqlite"
    lastValue: true
    file: artifacts/gimbal_tests.db

The plugin will error out because it doesn't create the artifcats directory. We need to use mkdirp module to create the directory prior to initializing sqlite3.

Workspaces

A repo may have multiple things that need testing and each thing may have different needs. For example, a repo may have a backend and frontend and while they may use node modules (may not also) the backend doesn't need UI performance testing while the frontend may.

We need to be able to handle a single project but also scale up to multiple projects in a given run.

The other thing is a repo can just define multiple projects and will execute this tool once per project. Sharing configs would require config merging to allow a base config to be extended. This is where javascript configs (per #2) would really be useful not that yml and json files couldn't be merged.

Production README

During dev, we had too much refactoring to count on a flushed out README. Now that we are in a more stable position, we should look at having a production version of the README. Things like how to install, how to use, that sort of stuff and we can look at other popular libs like eslint and such.

We can discuss whether we want a huge README or keep it simple and link to markdown files in a docs directory or wiki or github pages or a mix of those. I'd personally prefer more verbose docs separate from the README but give examples of the different commands in the README.

We will also want badges like a npm badge (yes, we aren't in npm but the package name is known), code coverage (yes, we have zero tests so once we do), CircleCI build status (actually exists but there is a step to enable this for a private repo).

Refactor module default configs merging

The starting issue is we were loading and merging configs for modules in this fashion:

const sizeConfig = Config.get('configs.size', defaultConfig);

However, since there is an array in the defaultConfig and what may be defined in configs.size (threshold is an array), the two arrays would be concatenated which isn't what is expected.

To bandaid fix this, the following was done:

const sizeConfig = {
   ...defaultConfig,
   ...Config.get('configs.size'),
};

However, this is then just a shallow merging. When we passed the defaultConfig as the second arg of Config.get(), internally deepmerge is used so objects and arrays are merged. The only reason, so far, that we don't want to pass defaultConfig is because it concatenates arrays for thresholds. Instead, we want to only add items to the default array if a conflicting item is not found, else override that default item. Code to explain what we want:

const defaultArray = [
  { path: './foo', maxSize: 123 },
  { path: './bar', maxSize: 456 },
];
const userArray = [
  { path: './baz', maxSize: 789 },
  { path: './bar', maxSize: 654 },
];

userArray.forEach(item => {
  const match = defaultArray.find(defaultItem => defaultItem.path === item.path);

  if (match) {
    // if a match was found in defaultArray, apply new configs onto it
    Object.assign(match, item);
  } else {
    // if not match was found, add item to that array
    defaultArray.push(item);
  }
});

result should be:

[
  { path: './foo', maxSize: 123 },
  { path: './bar', maxSize: 654 },
  { path: './baz', maxSize: 789 },
]

deepmerge does allow you to pass in an arrayMerge option that we can use to accomplish this and it needs to be done for all modules that load user configs and have default configs. arrayMerge doesn't provide the key so you just have to guess or figure it out (what array is being merged as threshold may not be the only array) so customMerge may have to be used as it provides the key. And maybe use both together... either way, we can utilize deepmerge to accomplish this and get back deep merging.

Monorepo

We should think how we want to architect things. Do we want one node module to have everything or do we want to split the core, modules and plugins into separate node modules to allow smaller custom installs. We could use lerna to handle the monorepo structure.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.