diff --git a/.gitignore b/.gitignore
index da8c3986e..ba435e214 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,7 +16,9 @@ erl_crash.dump
 /config/*.secret.exs
 
 .env.production
+.env.test
 .env
+.env.2
 
 setup_db.psql
 
diff --git a/config/config.exs b/config/config.exs
index 5626222b5..bc8ddeba9 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -16,6 +16,7 @@ config :mobilizon, :instance,
   hostname: System.get_env("MOBILIZON_INSTANCE_HOST") || "localhost",
   registrations_open: System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_OPEN") || false,
   repository: Mix.Project.config()[:source_url],
+  allow_relay: true,
   remote_limit: 100_000,
   upload_limit: 16_000_000,
   avatar_upload_limit: 2_000_000,
@@ -109,6 +110,9 @@ config :auto_linker,
 config :phoenix, :format_encoders, json: Jason, "activity-json": Jason
 config :phoenix, :json_library, Jason
 
+config :http_signatures,
+  adapter: Mobilizon.Service.HTTPSignatures.Signature
+
 config :mobilizon, Mobilizon.Service.Geospatial.Nominatim,
   endpoint:
     System.get_env("GEOSPATIAL_NOMINATIM_ENDPOINT") || "https://nominatim.openstreetmap.org",
diff --git a/config/dev.exs b/config/dev.exs
index b438a25b3..21c109e0b 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -11,7 +11,9 @@ config :mobilizon, MobilizonWeb.Endpoint,
     port: System.get_env("MOBILIZON_INSTANCE_PORT") || 4000
   ],
   url: [
-    host: System.get_env("MOBILIZON_INSTANCE_HOST") || "mobilizon.local"
+    host: System.get_env("MOBILIZON_INSTANCE_HOST") || "mobilizon.local",
+    port: 80,
+    scheme: "http"
   ],
   debug_errors: true,
   code_reloader: true,
diff --git a/js/package.json b/js/package.json
index 3250a61dc..cd35133be 100644
--- a/js/package.json
+++ b/js/package.json
@@ -56,6 +56,7 @@
     "chai": "^4.2.0",
     "dotenv-webpack": "^1.7.0",
     "eslint": "^6.0.1",
+    "graphql-cli": "^3.0.12",
     "node-sass": "^4.11.0",
     "patch-package": "^6.1.2",
     "sass-loader": "^7.1.0",
diff --git a/js/src/App.vue b/js/src/App.vue
index 2be5576e2..5f6d14d7f 100644
--- a/js/src/App.vue
+++ b/js/src/App.vue
@@ -98,6 +98,7 @@ export default class App extends Vue {
 @import "~buefy/src/scss/components/tag";
 @import "~buefy/src/scss/components/taginput";
 @import "~buefy/src/scss/components/upload";
+@import "~buefy/src/scss/components/radio";
 
 .router-enter-active,
 .router-leave-active {
diff --git a/js/src/api/_entrypoint.ts b/js/src/api/_entrypoint.ts
index ff2558d33..16de19cd8 100644
--- a/js/src/api/_entrypoint.ts
+++ b/js/src/api/_entrypoint.ts
@@ -5,7 +5,7 @@
  *
  * Example: framameet.org
  */
-export const MOBILIZON_INSTANCE_HOST = process.env.MOBILIZON_INSTANCE_HOST;
+export const MOBILIZON_INSTANCE_HOST = window.location.hostname;
 
 /**
  * URL on which the API is. "/api" will be added at the end
@@ -14,7 +14,7 @@ export const MOBILIZON_INSTANCE_HOST = process.env.MOBILIZON_INSTANCE_HOST;
  *
  * Example: https://framameet.org
  */
-export const GRAPHQL_API_ENDPOINT = process.env.GRAPHQL_API_ENDPOINT;
+export const GRAPHQL_API_ENDPOINT = window.location.origin;
 
 /**
  * URL with path on which the API is. Replaces GRAPHQL_API_ENDPOINT if used
@@ -23,4 +23,4 @@ export const GRAPHQL_API_ENDPOINT = process.env.GRAPHQL_API_ENDPOINT;
  *
  * Example: https://framameet.org/api
  */
-export const GRAPHQL_API_FULL_PATH = process.env.GRAPHQL_API_FULL_PATH;
+export const GRAPHQL_API_FULL_PATH = `${window.location.origin}/api`;
diff --git a/js/src/components/Account/ActorLink.vue b/js/src/components/Account/ActorLink.vue
new file mode 100644
index 000000000..94ca6839a
--- /dev/null
+++ b/js/src/components/Account/ActorLink.vue
@@ -0,0 +1,21 @@
+<template>
+    <span>
+        <router-link v-if="actor.domain === null"
+                     :to="{name: 'Profile', params: { name: actor.preferredUsername } }"
+        >
+            <slot></slot>
+        </router-link>
+        <a v-else :href="actor.url">
+            <slot></slot>
+        </a>
+    </span>
+</template>
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator';
+import { IActor } from '@/types/actor';
+
+@Component
+export default class ActorLink extends Vue {
+  @Prop() actor!: IActor;
+}
+</script>
\ No newline at end of file
diff --git a/js/src/graphql/event.ts b/js/src/graphql/event.ts
index 48ad5381f..3779894bd 100644
--- a/js/src/graphql/event.ts
+++ b/js/src/graphql/event.ts
@@ -51,6 +51,7 @@ export const FETCH_EVENT = gql`
         preferredUsername,
         domain,
         name,
+        url,
       },
       # attributedTo {
       #     avatar {
@@ -141,11 +142,12 @@ export const CREATE_EVENT = gql`
   $title: String!,
   $description: String!,
   $organizerActorId: ID!,
-  $category: String!,
+  $category: String,
   $beginsOn: DateTime!,
   $picture: PictureInput,
   $tags: [String],
-  $physicalAddress: AddressInput!
+  $physicalAddress: AddressInput,
+  $visibility: EventVisibility
   ) {
     createEvent(
       title: $title,
@@ -155,7 +157,8 @@ export const CREATE_EVENT = gql`
       category: $category,
       picture: $picture,
       tags: $tags,
-      physicalAddress: $physicalAddress
+      physicalAddress: $physicalAddress,
+      visibility: $visibility
     ) {
       id,
       uuid,
@@ -172,7 +175,7 @@ export const EDIT_EVENT = gql`
   $title: String!,
   $description: String!,
   $organizerActorId: Int!,
-  $category: String!
+  $category: String
   ) {
     EditEvent(title: $title, description: $description, organizerActorId: $organizerActorId, category: $category) {
       uuid
diff --git a/js/src/types/event.model.ts b/js/src/types/event.model.ts
index 50f1eda79..841e092bb 100644
--- a/js/src/types/event.model.ts
+++ b/js/src/types/event.model.ts
@@ -53,7 +53,7 @@ export interface IEvent {
   title: string;
   slug: string;
   description: string;
-  category: Category;
+  category: Category|null;
 
   beginsOn: Date;
   endsOn: Date;
diff --git a/js/src/views/Event/Create.vue b/js/src/views/Event/Create.vue
index 0de44411e..2a0954ed7 100644
--- a/js/src/views/Event/Create.vue
+++ b/js/src/views/Event/Create.vue
@@ -6,6 +6,11 @@
     <div v-if="$apollo.loading">Loading...</div>
     <div class="columns is-centered" v-else>
       <form class="column is-two-thirds-desktop" @submit="createEvent">
+        <h2 class="subtitle">
+          <translate>
+            General informations
+          </translate>
+        </h2>
         <picture-upload v-model="pictureFile" />
 
         <b-field :label="$gettext('Title')">
@@ -24,7 +29,7 @@
           <editor v-model="event.description" />
         </div>
 
-        <b-field :label="$gettext('Category')">
+        <!--<b-field :label="$gettext('Category')">
           <b-select placeholder="Select a category" v-model="event.category">
             <option
               v-for="category in categories"
@@ -32,9 +37,30 @@
               :key="category"
             >{{ $gettext(category) }}</option>
           </b-select>
-        </b-field>
+        </b-field>-->
 
-        <button class="button is-primary">
+        <h2 class="subtitle">
+          <translate>
+            Visibility
+          </translate>
+        </h2>
+          <label class="label">{{ $gettext('Event visibility') }}</label>
+          <div class="field">
+            <b-radio v-model="event.visibility"
+                     name="name"
+                     :native-value="EventVisibility.PUBLIC">
+              <translate>Visible everywhere on the web (public)</translate>
+            </b-radio>
+          </div>
+          <div class="field">
+            <b-radio v-model="event.visibility"
+                     name="name"
+                     :native-value="EventVisibility.PRIVATE">
+              <translate>Only accessible through link and search (private)</translate>
+            </b-radio>
+          </div>
+
+          <button class="button is-primary">
           <translate>Create my event</translate>
         </button>
       </form>
@@ -50,6 +76,7 @@ import {
       Category,
       IEvent,
       EventModel,
+      EventVisibility,
     } from '@/types/event.model';
 import { LOGGED_PERSON } from '@/graphql/actor';
 import { IPerson, Person } from '@/types/actor';
@@ -76,9 +103,10 @@ export default class CreateEvent extends Vue {
   @Prop({ required: false, type: String }) uuid!: string;
 
   loggedPerson: IPerson = new Person();
-  categories: string[] = Object.keys(Category);
+  /*categories: string[] = Object.keys(Category);*/
   event: IEvent = new EventModel();
   pictureFile: File | null = null;
+  EventVisibility = EventVisibility;
 
   created() {
     const now = new Date();
@@ -181,4 +209,4 @@ export default class CreateEvent extends Vue {
   //   }
   // }
 }
-</script>
+</script>
\ No newline at end of file
diff --git a/js/src/views/Event/Event.vue b/js/src/views/Event/Event.vue
index 74b638250..7fb7f6f33 100644
--- a/js/src/views/Event/Event.vue
+++ b/js/src/views/Event/Event.vue
@@ -92,19 +92,17 @@
                 </b-modal>
               </div>
               <div class="organizer">
-                <router-link
-                        :to="{name: 'Profile', params: { name: event.organizerActor.preferredUsername } }"
-                >
-                <translate
-                        :translate-params="{name: event.organizerActor.name ? event.organizerActor.name : event.organizerActor.preferredUsername}"
-                        v-if="event.organizerActor">By %{ name }</translate>
+                <actor-link :actor="event.organizerActor">
+                  <translate
+                          :translate-params="{name: event.organizerActor.name ? event.organizerActor.name : event.organizerActor.preferredUsername}"
+                          v-if="event.organizerActor">By %{ name }</translate>
                   <figure v-if="event.organizerActor.avatar" class="image is-48x48">
                     <img
                             class="is-rounded"
                             :src="event.organizerActor.avatar.url"
                             :alt="$gettextInterpolate('%{actor}\'s avatar', {actor: event.organizerActor.preferredUsername})" />
                   </figure>
-                </router-link>
+                </actor-link>
               </div>
             </div>
           </div>
@@ -242,9 +240,11 @@ import DateCalendarIcon from '@/components/Event/DateCalendarIcon.vue';
 import BIcon from 'buefy/src/components/icon/Icon.vue';
 import EventCard from '@/components/Event/EventCard.vue';
 import EventFullDate from '@/components/Event/EventFullDate.vue';
+import ActorLink from '@/components/Account/ActorLink.vue';
 
 @Component({
   components: {
+    ActorLink,
     EventFullDate,
     EventCard,
     BIcon,
diff --git a/js/vue.config.js b/js/vue.config.js
index 32315328d..48a54826b 100644
--- a/js/vue.config.js
+++ b/js/vue.config.js
@@ -4,7 +4,7 @@ const path = require('path');
 module.exports = {
   pluginOptions: {
     webpackBundleAnalyzer: {
-      openAnalyzer: false
+      analyzerMode: 'disabled'
     }
   },
   lintOnSave: false,
diff --git a/js/yarn.lock b/js/yarn.lock
index d449524c3..16530c759 100644
--- a/js/yarn.lock
+++ b/js/yarn.lock
@@ -29,6 +29,17 @@
     semver "^5.4.1"
     source-map "^0.5.0"
 
+"@babel/generator@7.0.0-beta.38":
+  version "7.0.0-beta.38"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.38.tgz#6115a66663e3adfd1d6844029ffb2354680182eb"
+  integrity sha512-aOHQPhsEyaB6p2n+AK981+onHoc+Ork9rcAQVSUJR33wUkGiWRpu6/C685knRyIZVsKeSdG5Q4xMiYeFUhuLzA==
+  dependencies:
+    "@babel/types" "7.0.0-beta.38"
+    jsesc "^2.5.1"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
 "@babel/generator@^7.5.5":
   version "7.5.5"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.5.tgz#873a7f936a3c89491b43536d12245b626664e3cf"
@@ -669,6 +680,15 @@
     globals "^11.1.0"
     lodash "^4.17.13"
 
+"@babel/types@7.0.0-beta.38":
+  version "7.0.0-beta.38"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.38.tgz#2ce2443f7dc6ad535a67db4940cbd34e64035a6f"
+  integrity sha512-SAtyEjmA7KiEoL2eAOAUM6M9arQJGWxJKK0S9x0WyPOosHS420RXoxPhn57u/8orRnK8Kxm0nHQQNTX203cP1Q==
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^2.0.0"
+
 "@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5":
   version "7.5.5"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.5.tgz#97b9f728e182785909aa4ab56264f090a028d18a"
@@ -708,9 +728,9 @@
   integrity sha512-HOJ20Kc93DkDVvjwHyHawPwPkX44sIrbXazAUDiUXaY2R9JwQGo2PhFfnQtdrsIe4igjG2fPgMra7NYw7qhy0A==
 
 "@hapi/hoek@8.x.x":
-  version "8.0.2"
-  resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.0.2.tgz#f63a5ff00e891a4e7aa98f11119f9515c6672032"
-  integrity sha512-O6o6mrV4P65vVccxymuruucb+GhP2zl9NLCG8OdoFRS8BEGw3vwpPp20wpAtpbQQxz1CEUtmxJGgWhjq1XA3qw==
+  version "8.2.1"
+  resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.2.1.tgz#924af04cbb22e17359c620d2a9c946e63f58eb77"
+  integrity sha512-JPiBy+oSmsq3St7XlipfN5pNA6bDJ1kpa73PrK/zR29CVClDVqy04AanM/M/qx5bSF+I61DdCfAvRrujau+zRg==
 
 "@hapi/joi@^15.0.1":
   version "15.1.0"
@@ -728,9 +748,9 @@
   integrity sha512-JOfdekTXnJexfE8PyhZFyHvHjt81rBFSAbTIRAhF2vv/2Y1JzoKsGqxH/GpZJoF7aEfYok8JVcAHmSz1gkBieA==
 
 "@hapi/topo@3.x.x":
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.2.tgz#57cc1317be1a8c5f47c124f9b0e3c49cd78424d2"
-  integrity sha512-r+aumOqJ5QbD6aLPJWqVjMAPsx5pZKz+F5yPqXZ/WWG9JTtHbQqlzrJoknJ0iJxLj9vlXtmpSdjlkszseeG8OA==
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.3.tgz#c7a02e0d936596d29f184e6d7fdc07e8b5efce11"
+  integrity sha512-JmS9/vQK6dcUYn7wc2YZTqzIKubAQcJKu2KCKAru6es482U5RT5fP1EXCPtlXpiK7PR0On/kpQKI4fRKkzpZBQ==
   dependencies:
     "@hapi/hoek" "8.x.x"
 
@@ -743,6 +763,21 @@
     cssnano-preset-default "^4.0.0"
     postcss "^7.0.0"
 
+"@kbrandwijk/swagger-to-graphql@2.4.3":
+  version "2.4.3"
+  resolved "https://registry.yarnpkg.com/@kbrandwijk/swagger-to-graphql/-/swagger-to-graphql-2.4.3.tgz#7c0fb2410eb0b6b9cc81fad28cc20f9386153cf1"
+  integrity sha512-CNVsCrMge/jq6DCT5buNZ8PACY9RTvPJbCNoIcndfkJOCsNxOx9dnc5qw4pHZdHi8GS6l3qlgkuFKp33iD8J2Q==
+  dependencies:
+    babel-runtime "^6.25.0"
+    isomorphic-fetch "^2.2.1"
+    js-yaml "^3.8.4"
+    json-schema-ref-parser "^3.1.2"
+    lodash "^4.16.4"
+    node-request-by-swagger "^1.0.6"
+    request "^2.75.0"
+    request-promise "^4.1.1"
+    yargs "^8.0.2"
+
 "@mrmlnc/readdir-enhanced@^2.2.1":
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -778,9 +813,9 @@
     "@types/babel-types" "*"
 
 "@types/chai@^4.1.7":
-  version "4.1.7"
-  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a"
-  integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.0.tgz#2478260021408dec32c123a7cad3414beb811a07"
+  integrity sha512-zw8UvoBEImn392tLjxoavuonblX/4Yb9ha4KBU10FirCfwgzhKO0dvyJSF9ByxV1xK1r2AgnAi/tvQaLgxQqxA==
 
 "@types/eslint-visitor-keys@^1.0.0":
   version "1.0.0"
@@ -812,9 +847,9 @@
   integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==
 
 "@types/leaflet@^1.4.4":
-  version "1.4.7"
-  resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.4.7.tgz#96c4388e4f9cc599e85dbe2796e7df81dffb7ccb"
-  integrity sha512-wk6zQCFm8qXABeNrOQD4X7eYydhYydSBRdN82JVqyR4APe0i1kgvfBOc6rbtJ/A445tOUDTXdTGdCFh2Gapxgg==
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.0.tgz#a401eb9ec9e1c0c340454660f54962f29f048b7d"
+  integrity sha512-il6N/CP31AjvhYkWcQg9RAo/irfA88Qgs4r2AY8mVOU+btF4d60d/nI4M2rFuV+HyByQCItFfwj0yoPRMoMurQ==
   dependencies:
     "@types/geojson" "*"
 
@@ -834,9 +869,9 @@
   integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
 
 "@types/node@*", "@types/node@>=6":
-  version "12.6.8"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.8.tgz#e469b4bf9d1c9832aee4907ba8a051494357c12c"
-  integrity sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==
+  version "12.7.1"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.1.tgz#3b5c3a26393c19b400844ac422bd0f631a94d69d"
+  integrity sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==
 
 "@types/node@^8.0.7":
   version "8.10.51"
@@ -918,10 +953,10 @@
     lodash.kebabcase "^4.1.1"
     svg-tags "^1.0.0"
 
-"@vue/babel-preset-app@^3.9.2":
-  version "3.9.2"
-  resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-3.9.2.tgz#b72a9b06abbe3f8f272783be13951271277be338"
-  integrity sha512-0suuCbu4jkVcVYBjPmuKxeDbrhwThYZHu3DUmtsVuOzFEGeXmco60VmXveniL/bnDUdZyknSuYP4FxgS34gw9w==
+"@vue/babel-preset-app@^3.10.0":
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-3.10.0.tgz#3f89d631dd0f174c8a72e769b55f081c533c4677"
+  integrity sha512-NzJLI4Qe0SYm9gVHQC9RXyP0YcPjI28TmZ0ds2RJa9NO96LXHLES2U1HqiMDN4+CVjOQFrWUNd7wWeaETRPXbg==
   dependencies:
     "@babel/helper-module-imports" "^7.0.0"
     "@babel/plugin-proposal-class-properties" "^7.0.0"
@@ -984,28 +1019,28 @@
     "@vue/babel-plugin-transform-vue-jsx" "^1.0.0"
     camelcase "^5.0.0"
 
-"@vue/cli-overlay@^3.9.0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-3.9.0.tgz#11f513d1fa11b0135fb8ba8b88d228df0dc542e0"
-  integrity sha512-QfyvpJl2ChehBT2qzb5EvW921JxW94uFL3+lHa6VT42ImH8awrvkTGZmxTQWhHvATa7r0LKy7M7ZRMyo547esg==
+"@vue/cli-overlay@^3.10.0":
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-3.10.0.tgz#9266c96fb2bffd35ca96edd8e1e1284ca8c00c94"
+  integrity sha512-DQCY6WIl1UN1nOuPirW63CcYWSBdIn6s4zdGfFodCfV+0PAEXGcrfNStygG+IKUsydQaJGTneV7SFxcS+9gyzA==
 
 "@vue/cli-plugin-babel@^3.6.0":
-  version "3.9.2"
-  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-babel/-/cli-plugin-babel-3.9.2.tgz#8ff962a383aaeafd2b280998428a57ea23e9539c"
-  integrity sha512-XqfmGjUGnnJ3NA+HC31F6nkBvB9pFDhk4Lxeao8ZNJcEjKNEBYjlmHunJQdIe/jEXXum6U+U/ZE6DjDStHTIMw==
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-babel/-/cli-plugin-babel-3.10.0.tgz#3c5300bd6daf30b53292a6c3982e3a681cba2c18"
+  integrity sha512-NHrg6ZYN2fh5ZiMMzCNRuDlH9mcTOu+GIti1Va/zPnG3qMkX2iZ0zZGFaOCltIFoVSXdyOfa0sMtJGDoP9Q7ZA==
   dependencies:
     "@babel/core" "^7.0.0"
-    "@vue/babel-preset-app" "^3.9.2"
-    "@vue/cli-shared-utils" "^3.9.0"
+    "@vue/babel-preset-app" "^3.10.0"
+    "@vue/cli-shared-utils" "^3.10.0"
     babel-loader "^8.0.5"
     webpack ">=4 < 4.29"
 
 "@vue/cli-plugin-e2e-nightwatch@^3.6.0":
-  version "3.9.2"
-  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-e2e-nightwatch/-/cli-plugin-e2e-nightwatch-3.9.2.tgz#7ed58c576eb4b8559e1fb86458ea11693317b832"
-  integrity sha512-olDeE3C5Fmd8ZG2SxNIjWKyhLzi8RXaDNKIFw7ZNrdoJKe8Av0OAweSjP6y5iRApgOQOX2JfS1vum47LC/Dh8g==
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-e2e-nightwatch/-/cli-plugin-e2e-nightwatch-3.10.0.tgz#ed7583e21ccce1c61d4268fba701dfb39582b7c2"
+  integrity sha512-F6qIqHUlFfvJUSBB4fZbRAiwTkt0Pd0xKgasV0XwMohYLGD7aB/cf62ORwPU2Rl2+sZ2rN1k6VyEeVnXLcBduA==
   dependencies:
-    "@vue/cli-shared-utils" "^3.9.0"
+    "@vue/cli-shared-utils" "^3.10.0"
     chromedriver "^2.46.0"
     deepmerge "^3.2.0"
     execa "^1.0.0"
@@ -1013,21 +1048,21 @@
     selenium-server "^3.141.59"
 
 "@vue/cli-plugin-pwa@^3.6.0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-pwa/-/cli-plugin-pwa-3.9.0.tgz#5b26d91bc7dd66fcddd593f47e18a8c88b2e3876"
-  integrity sha512-wOoSePJ7nbWiV8jRAt2i5IM3pWrf2TQZMcaf062wMLva/cLDOivENDGOWxL8kkCjfduQGXUkFYtqZCT1QKph8g==
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-pwa/-/cli-plugin-pwa-3.10.0.tgz#2bf81d15d9bfe629ed8b3b8344ba7687ddca258a"
+  integrity sha512-Jd5HhiZWaSgNhy51uRe15HjTxQQTgCTTJaXL7ARnmWRrOW5WgTwE+rc4rq5e2iuWaNYSnzgyB8MpIflnJ+4kLQ==
   dependencies:
-    "@vue/cli-shared-utils" "^3.9.0"
+    "@vue/cli-shared-utils" "^3.10.0"
     webpack ">=4 < 4.29"
     workbox-webpack-plugin "^3.6.3"
 
 "@vue/cli-plugin-typescript@^3.6.0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-typescript/-/cli-plugin-typescript-3.9.0.tgz#8969f2df898a68b4c1d49f5a928ec9ba35a0c0fe"
-  integrity sha512-QXL98MLM2gdqcrLkEG3bjwyQDIhzKdJqUdVghH/ZAttSj5G3hDKklI5HPqz3TJV7FVDOocFr1szP2BcXCCLh8Q==
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-typescript/-/cli-plugin-typescript-3.10.0.tgz#a69f96caba83106c35eedb8cde54840826fab6ef"
+  integrity sha512-zA5UVw6eU3xVNEoFYa0WmxQvRLcir80daKrVwG7gBcH50T4uHA7i7ZLdsLLehFq8foV3N/tbDLXDY+XwVjEWog==
   dependencies:
     "@types/webpack-env" "^1.13.9"
-    "@vue/cli-shared-utils" "^3.9.0"
+    "@vue/cli-shared-utils" "^3.10.0"
     fork-ts-checker-webpack-plugin "^0.5.2"
     globby "^9.2.0"
     ts-loader "^5.3.3"
@@ -1036,25 +1071,25 @@
     yorkie "^2.0.0"
 
 "@vue/cli-plugin-unit-mocha@^3.6.0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-unit-mocha/-/cli-plugin-unit-mocha-3.9.0.tgz#4fad75c7df06a2190305d591e1992c4f1f126dca"
-  integrity sha512-ukaPvFExcZ3Bw/ERpuVJX6+h29tY2zYYFdOQ6Vv4+MyL/tUfzSoWOB9y065mqe0nBzvRJlhq5FJ8zMYFkoSdow==
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/cli-plugin-unit-mocha/-/cli-plugin-unit-mocha-3.10.0.tgz#1ef0c6bd56e2b4f660c2b641444fd7cb208e34cf"
+  integrity sha512-78yf/R0qxKrbLnFh8tksZ90xRkAW/iVheqHDlQp5QOhJwXJmJVUi+Qm7UxBoRomkg1scuSSugSqT7fyCbkVS9w==
   dependencies:
-    "@vue/cli-shared-utils" "^3.9.0"
+    "@vue/cli-shared-utils" "^3.10.0"
     jsdom "^13.2.0"
     jsdom-global "^3.0.2"
     mocha "^5.2.0"
     mocha-webpack "^2.0.0-beta.0"
 
 "@vue/cli-service@^3.6.0":
-  version "3.9.3"
-  resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-3.9.3.tgz#4bd5786465afb8b608c5c7fc9661390e747ea756"
-  integrity sha512-CZE9PP4HH9bK4qAaLbTUB3tubggI+aRSbgB/QYSZrVlhtMpuVFZPj2QHbIvJQZTI2cG6LFQtLTZWXKeqo5lbAQ==
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-3.10.0.tgz#1e61afac9eeed5d902c124715c29719abeb743c5"
+  integrity sha512-aQaAjtkpSl4XFBM7Di9doh4GvHp1H8/H1QJKRK8bPJ5MVbt8Lt4tBo+YgK9Qs/9x0mrxCAa5UrR9+8ZWIQs2Zw==
   dependencies:
     "@intervolga/optimize-cssnano-plugin" "^1.0.5"
     "@soda/friendly-errors-webpack-plugin" "^1.7.1"
-    "@vue/cli-overlay" "^3.9.0"
-    "@vue/cli-shared-utils" "^3.9.0"
+    "@vue/cli-overlay" "^3.10.0"
+    "@vue/cli-shared-utils" "^3.10.0"
     "@vue/component-compiler-utils" "^2.6.0"
     "@vue/preload-webpack-plugin" "^1.1.0"
     "@vue/web-component-wrapper" "^1.2.0"
@@ -1108,10 +1143,10 @@
     webpack-dev-server "^3.4.1"
     webpack-merge "^4.2.1"
 
-"@vue/cli-shared-utils@^3.9.0":
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-3.9.0.tgz#cb56a443bf763a873849a11d07e9e7638aa16cc2"
-  integrity sha512-wumeMZTz5aQ+1Y6uxTKegIsgOXEWT3hT8f9sW2mj5SwNDVyQ+AHZTgSynYExTUJg3dH81uKgFDUpPdAvGxzh8g==
+"@vue/cli-shared-utils@^3.10.0":
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-3.10.0.tgz#9d156f3c0ef675a939319062489e98c8d3d80f7e"
+  integrity sha512-i96XBUtLdWeKFCC/ot12ngqnVikN/dXpelGdyxvNZczCkX7Je0FUdrZkiw0+uTYTu1RmuYWpLs+vb/YQerjiWg==
   dependencies:
     "@hapi/joi" "^15.0.1"
     chalk "^2.4.1"
@@ -1180,9 +1215,9 @@
     "@typescript-eslint/parser" "^1.1.0"
 
 "@vue/preload-webpack-plugin@^1.1.0":
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.0.tgz#d768dba004261c029b53a77c5ea2d5f9ee4f3cce"
-  integrity sha512-rcn2KhSHESBFMPj5vc5X2pI9bcBNQQixvJXhD5gZ4rN2iym/uH2qfDSQfUS5+qwiz0a85TCkeUs6w6jxFDudbw==
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.1.tgz#18723530d304f443021da2292d6ec9502826104a"
+  integrity sha512-8VCoJeeH8tCkzhkpfOkt+abALQkS11OIHhte5MBzYaKMTqK0A3ZAKEUVAffsOklhEv7t0yrQt696Opnu9oAx+w==
 
 "@vue/test-utils@^1.0.0-beta.29":
   version "1.0.0-beta.29"
@@ -1568,9 +1603,9 @@ acorn-globals@^3.0.0:
     acorn "^4.0.4"
 
 acorn-globals@^4.3.0:
-  version "4.3.2"
-  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.2.tgz#4e2c2313a597fd589720395f6354b41cd5ec8006"
-  integrity sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==
+  version "4.3.3"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.3.tgz#a86f75b69680b8780d30edd21eee4e0ea170c05e"
+  integrity sha512-vkR40VwS2SYO98AIeFvzWWh+xyc2qi9s7OoXSFEGIP/rOJKzjnhykaZJNnHdoq4BL2gGxI5EZOU16z896EYnOQ==
   dependencies:
     acorn "^6.0.1"
     acorn-walk "^6.0.1"
@@ -1650,10 +1685,10 @@ acorn@^5.0.0, acorn@^5.2.1, acorn@^5.3.0, acorn@^5.4.0, acorn@^5.4.1, acorn@^5.5
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
   integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
 
-acorn@^6.0.1, acorn@^6.0.4, acorn@^6.0.7, acorn@^6.1.1, acorn@^6.2.0:
-  version "6.2.1"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.1.tgz#3ed8422d6dec09e6121cc7a843ca86a330a86b51"
-  integrity sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==
+acorn@^6.0.1, acorn@^6.0.4, acorn@^6.0.7, acorn@^6.1.1, acorn@^6.2.1:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e"
+  integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==
 
 address@^1.0.3:
   version "1.1.0"
@@ -1668,16 +1703,33 @@ agent-base@2:
     extend "~3.0.0"
     semver "~5.0.1"
 
+agent-base@4, agent-base@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
+  integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
+  dependencies:
+    es6-promisify "^5.0.0"
+
 ajv-errors@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
   integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==
 
-ajv-keywords@^3.1.0:
+ajv-keywords@^3.1.0, ajv-keywords@^3.4.1:
   version "3.4.1"
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da"
   integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==
 
+ajv@5, ajv@^5.5.1:
+  version "5.5.2"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
+  integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=
+  dependencies:
+    co "^4.6.0"
+    fast-deep-equal "^1.0.0"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.3.0"
+
 ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5:
   version "6.10.2"
   resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
@@ -1719,11 +1771,18 @@ ansi-colors@^3.0.0:
   resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
   integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
 
-ansi-escapes@^3.2.0:
+ansi-escapes@^3.0.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
   integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
 
+ansi-escapes@^4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.2.1.tgz#4dccdb846c3eee10f6d64dea66273eab90c37228"
+  integrity sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==
+  dependencies:
+    type-fest "^0.5.2"
+
 ansi-html@0.0.7:
   version "0.0.7"
   resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
@@ -1744,7 +1803,7 @@ ansi-regex@^4.1.0:
   resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
   integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
 
-ansi-styles@^2.2.1:
+ansi-styles@^2.0.1, ansi-styles@^2.2.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
   integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
@@ -1782,13 +1841,13 @@ apollo-absinthe-upload-link@^1.5.0:
     rxjs "~6.2.2"
 
 apollo-cache-inmemory@^1.5.1:
-  version "1.6.2"
-  resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.2.tgz#bbf2e4e1eacdf82b2d526f5c2f3b37e5acee3c5e"
-  integrity sha512-AyCl3PGFv5Qv1w4N9vlg63GBPHXgMCekZy5mhlS042ji0GW84uTySX+r3F61ZX3+KM1vA4m9hQyctrEGiv5XjQ==
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.3.tgz#826861d20baca4abc45f7ca7a874105905b8525d"
+  integrity sha512-S4B/zQNSuYc0M/1Wq8dJDTIO9yRgU0ZwDGnmlqxGGmFombOZb9mLjylewSfQKmjNpciZ7iUIBbJ0mHlPJTzdXg==
   dependencies:
     apollo-cache "^1.3.2"
     apollo-utilities "^1.3.2"
-    optimism "^0.9.0"
+    optimism "^0.10.0"
     ts-invariant "^0.4.0"
     tslib "^1.9.3"
 
@@ -1824,9 +1883,9 @@ apollo-client@2.5.1:
     zen-observable "^0.8.0"
 
 apollo-client@^2.0.4:
-  version "2.6.3"
-  resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.3.tgz#9bb2d42fb59f1572e51417f341c5f743798d22db"
-  integrity sha512-DS8pmF5CGiiJ658dG+mDn8pmCMMQIljKJSTeMNHnFuDLV0uAPZoeaAwVFiAmB408Ujqt92oIZ/8yJJAwSIhd4A==
+  version "2.6.4"
+  resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.4.tgz#872c32927263a0d34655c5ef8a8949fbb20b6140"
+  integrity sha512-oWOwEOxQ9neHHVZrQhHDbI6bIibp9SHgxaLRVPoGvOFy7OH5XUykZE7hBQAVxq99tQjBzgytaZffQkeWo1B4VQ==
   dependencies:
     "@types/zen-observable" "^0.8.0"
     apollo-cache "1.3.2"
@@ -1837,6 +1896,86 @@ apollo-client@^2.0.4:
     tslib "^1.9.3"
     zen-observable "^0.8.0"
 
+apollo-codegen-core@^0.20.0:
+  version "0.20.1"
+  resolved "https://registry.yarnpkg.com/apollo-codegen-core/-/apollo-codegen-core-0.20.1.tgz#56b6dd740f54b3f04e5db853ba1e1598388724c7"
+  integrity sha512-sanUIqXWyyDpxY3fYOVU+Hsxwxdj5fmn3Zcy6CcMGnWmh9o7tautQAuod2a63wrDs1jcNQcFq3EKIpeB+2xECw==
+  dependencies:
+    "@babel/generator" "7.0.0-beta.38"
+    "@babel/types" "7.0.0-beta.38"
+    common-tags "^1.5.1"
+    core-js "^2.5.3"
+    graphql-config "^2.0.1"
+
+apollo-codegen-flow-legacy@^0.20.0:
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/apollo-codegen-flow-legacy/-/apollo-codegen-flow-legacy-0.20.0.tgz#a9f1a0bb16c0fbde22b7dc7509b835d822861c67"
+  integrity sha512-kGjJNkkkob9gGYSIhwfdgOzkj0PuN4/QPhng4ckSaSCE+8E4Awyvk0P8LiYPKauHzHVjmJzxWLSG6kI0PQTNgA==
+  dependencies:
+    apollo-codegen-core "^0.20.0"
+
+apollo-codegen-flow@^0.20.0:
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/apollo-codegen-flow/-/apollo-codegen-flow-0.20.0.tgz#6d6219150235efd74620d421f42d96216292070d"
+  integrity sha512-XgKE19B0Q74PBLVqHP/77NcCFrcvrN9wi3CcotH+FV8BeHTjvpHlilTsQMmd2STPt19cCvY2Qtz0EOeLXTUQ2Q==
+  dependencies:
+    apollo-codegen-core "^0.20.0"
+    change-case "^3.0.1"
+    inflected "^2.0.3"
+
+apollo-codegen-scala@^0.20.0:
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/apollo-codegen-scala/-/apollo-codegen-scala-0.20.0.tgz#3ce29057cbb72f47806b27e6b780252dfa4fc349"
+  integrity sha512-NbnMOfUXXovlTGRj4mIZGXB9HvidQhwKfAmdYHox5peHPkjjsqEzxGCIuWCSnubWiCF2uHZnQoIkg4sXWf0KLw==
+  dependencies:
+    apollo-codegen-core "^0.20.0"
+    change-case "^3.0.1"
+    inflected "^2.0.3"
+
+apollo-codegen-swift@^0.20.0:
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/apollo-codegen-swift/-/apollo-codegen-swift-0.20.0.tgz#84a3f7b8d2c0f99fc65fb57acbe0abf9a9932f45"
+  integrity sha512-L9Y4StbXw0t/nuF+miz0ybSt/io6tsLc063Yeh1A8GCvhFFQyXE/yK0Rf3nO1Bl5Z9UZ5o8Aae9kK4GSWYIGNQ==
+  dependencies:
+    apollo-codegen-core "^0.20.0"
+    change-case "^3.0.1"
+    inflected "^2.0.3"
+
+apollo-codegen-typescript-legacy@^0.20.0:
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/apollo-codegen-typescript-legacy/-/apollo-codegen-typescript-legacy-0.20.0.tgz#e3dab94e6b8f0136f30d92a517c5dfd172452240"
+  integrity sha512-0/h5hce2FIGn6Y4+EHMeMINQxFwcgjw1vU+xV3KGaaEgyEAEQ3/n9pyz43M8mOm/JVgg8Eb4CtM1AtCkRQuFGw==
+  dependencies:
+    apollo-codegen-core "^0.20.0"
+
+apollo-codegen-typescript@^0.20.0:
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/apollo-codegen-typescript/-/apollo-codegen-typescript-0.20.0.tgz#a77eea6a68c0d09b29855667371bcd836cadfa78"
+  integrity sha512-mzlIJXz+5WPwzeALqRHHR9aPPEf6IlhSrjCawpUHmFU1NK9hgwbguYCEYZv9mKkYBUUgDY+9cGFK1cafJX70AQ==
+  dependencies:
+    apollo-codegen-core "^0.20.0"
+    change-case "^3.0.1"
+    inflected "^2.0.3"
+
+apollo-codegen@^0.20.2:
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/apollo-codegen/-/apollo-codegen-0.20.2.tgz#960972828651de74e043f8f92f6f819025a50f49"
+  integrity sha512-f95fPGoQoj+XcR7JWgR35mUYrD7RWT4kHbtSLs3aHeRFOKUHEWW2nHUNTOtQbbIdLulRuxPQCTvSddT7fFwhrA==
+  dependencies:
+    apollo-codegen-core "^0.20.0"
+    apollo-codegen-flow "^0.20.0"
+    apollo-codegen-flow-legacy "^0.20.0"
+    apollo-codegen-scala "^0.20.0"
+    apollo-codegen-swift "^0.20.0"
+    apollo-codegen-typescript "^0.20.0"
+    apollo-codegen-typescript-legacy "^0.20.0"
+    glob "^7.1.2"
+    graphql "^0.13.1"
+    node-fetch "^1.7.3"
+    rimraf "^2.6.2"
+    source-map-support "^0.5.0"
+    yargs "^10.0.3"
+
 apollo-link-dedup@^1.0.0:
   version "1.0.19"
   resolved "https://registry.yarnpkg.com/apollo-link-dedup/-/apollo-link-dedup-1.0.19.tgz#f0f58312c80b9bf0d927a53d5cad56875c679e14"
@@ -1946,11 +2085,6 @@ array-equal@^1.0.0:
   resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
   integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
 
-array-filter@~0.0.0:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
-  integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw=
-
 array-find-index@^1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
@@ -1966,16 +2100,6 @@ array-flatten@^2.1.0:
   resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
   integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
 
-array-map@~0.0.0:
-  version "0.0.0"
-  resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
-  integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=
-
-array-reduce@~0.0.0:
-  version "0.0.0"
-  resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b"
-  integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=
-
 array-union@^1.0.1, array-union@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
@@ -2063,15 +2187,22 @@ async-foreach@^0.1.3:
   integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
 
 async-limiter@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
-  integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
+  integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
 
 async@^1.5.2:
   version "1.5.2"
   resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
   integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=
 
+async@^2.6.1:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
+  integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
+  dependencies:
+    lodash "^4.17.14"
+
 asynckit@^0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -2162,7 +2293,7 @@ babel-plugin-transform-object-rest-spread@^6.26.0:
     babel-plugin-syntax-object-rest-spread "^6.8.0"
     babel-runtime "^6.26.0"
 
-babel-runtime@^6.18.0, babel-runtime@^6.26.0:
+babel-runtime@^6.18.0, babel-runtime@^6.25.0, babel-runtime@^6.26.0:
   version "6.26.0"
   resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
   integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
@@ -2191,9 +2322,9 @@ balanced-match@^1.0.0:
   integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
 
 base64-js@^1.0.2:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
-  integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
+  integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
 
 base@^0.11.1:
   version "0.11.2"
@@ -2252,7 +2383,7 @@ block-stream@*:
   dependencies:
     inherits "~2.0.0"
 
-bluebird@^3.1.1, bluebird@^3.5.1, bluebird@^3.5.5:
+bluebird@^3.1.1, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.5:
   version "3.5.5"
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
   integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
@@ -2262,7 +2393,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
   integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
 
-body-parser@1.19.0:
+body-parser@1.19.0, body-parser@^1.18.3:
   version "1.19.0"
   resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
   integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
@@ -2427,6 +2558,11 @@ buefy@^0.7.3:
   dependencies:
     bulma "0.7.5"
 
+buffer-equal-constant-time@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
+  integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=
+
 buffer-from@^1.0.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
@@ -2495,16 +2631,17 @@ cacache@^10.0.4:
     unique-filename "^1.1.0"
     y18n "^4.0.0"
 
-cacache@^11.3.2:
-  version "11.3.3"
-  resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc"
-  integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==
+cacache@^12.0.2:
+  version "12.0.2"
+  resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.2.tgz#8db03205e36089a3df6954c66ce92541441ac46c"
+  integrity sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==
   dependencies:
     bluebird "^3.5.5"
     chownr "^1.1.1"
     figgy-pudding "^3.5.1"
     glob "^7.1.4"
     graceful-fs "^4.1.15"
+    infer-owner "^1.0.3"
     lru-cache "^5.1.1"
     mississippi "^3.0.0"
     mkdirp "^0.5.1"
@@ -2570,7 +2707,7 @@ callsites@^3.0.0:
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
   integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
 
-camel-case@3.0.x:
+camel-case@3.0.x, camel-case@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
   integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
@@ -2622,9 +2759,9 @@ caniuse-api@^3.0.0:
     lodash.uniq "^4.5.0"
 
 caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000984:
-  version "1.0.30000985"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000985.tgz#0eb40f6c8a8c219155cbe43c4975c0efb4a0f77f"
-  integrity sha512-1ngiwkgqAYPG0JSSUp3PUDGPKKY59EK7NrGGX+VOxaKCNzRbNc7uXMny+c3VJfZxtoK3wSImTvG9T9sXiTw2+w==
+  version "1.0.30000989"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz#b9193e293ccf7e4426c5245134b8f2a56c0ac4b9"
+  integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==
 
 capture-stack-trace@^1.0.0:
   version "1.0.1"
@@ -2669,6 +2806,15 @@ chai@^4.2.0:
     pathval "^1.1.0"
     type-detect "^4.0.5"
 
+chalk@2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
+  integrity sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==
+  dependencies:
+    ansi-styles "^3.2.0"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.2.0"
+
 chalk@^1.1.1, chalk@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
@@ -2689,6 +2835,30 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4
     escape-string-regexp "^1.0.5"
     supports-color "^5.3.0"
 
+change-case@^3.0.1:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.1.0.tgz#0e611b7edc9952df2e8513b27b42de72647dd17e"
+  integrity sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==
+  dependencies:
+    camel-case "^3.0.0"
+    constant-case "^2.0.0"
+    dot-case "^2.1.0"
+    header-case "^1.0.0"
+    is-lower-case "^1.1.0"
+    is-upper-case "^1.1.0"
+    lower-case "^1.1.1"
+    lower-case-first "^1.0.0"
+    no-case "^2.3.2"
+    param-case "^2.1.0"
+    pascal-case "^2.0.0"
+    path-case "^2.1.0"
+    sentence-case "^2.1.0"
+    snake-case "^2.1.0"
+    swap-case "^1.1.0"
+    title-case "^2.1.0"
+    upper-case "^1.1.1"
+    upper-case-first "^1.1.0"
+
 character-parser@^2.1.1:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0"
@@ -2747,7 +2917,7 @@ chownr@^1.0.1, chownr@^1.1.1:
   resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6"
   integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==
 
-chrome-trace-event@^1.0.0:
+chrome-trace-event@^1.0.0, chrome-trace-event@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"
   integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==
@@ -2812,6 +2982,13 @@ cli-cursor@^2.1.0:
   dependencies:
     restore-cursor "^2.0.0"
 
+cli-cursor@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+  integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
+  dependencies:
+    restore-cursor "^3.1.0"
+
 cli-highlight@^2.1.0:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.1.tgz#2180223d51618b112f4509cf96e4a6c750b07e97"
@@ -2877,21 +3054,25 @@ cliui@^5.0.0:
     strip-ansi "^5.2.0"
     wrap-ansi "^5.1.0"
 
-clone-deep@^2.0.1:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713"
-  integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==
+clone-deep@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
+  integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
   dependencies:
-    for-own "^1.0.0"
     is-plain-object "^2.0.4"
-    kind-of "^6.0.0"
-    shallow-clone "^1.0.0"
+    kind-of "^6.0.2"
+    shallow-clone "^3.0.0"
 
 clone@^1.0.2:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
   integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
 
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+  integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
+
 co@~3.0.6:
   version "3.0.6"
   resolved "https://registry.yarnpkg.com/co/-/co-3.0.6.tgz#1445f226c5eb956138e68c9ac30167ea7d2e6bda"
@@ -2952,6 +3133,14 @@ color@^3.0.0:
     color-convert "^1.9.1"
     color-string "^1.5.2"
 
+columnify@^1.5.4:
+  version "1.5.4"
+  resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb"
+  integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=
+  dependencies:
+    strip-ansi "^3.0.0"
+    wcwidth "^1.0.0"
+
 combined-stream@^1.0.6, combined-stream@~1.0.6:
   version "1.0.8"
   resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@@ -2959,6 +3148,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
   dependencies:
     delayed-stream "~1.0.0"
 
+command-exists@^1.2.8:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.8.tgz#715acefdd1223b9c9b37110a149c6392c2852291"
+  integrity sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==
+
 commander@2.15.1:
   version "2.15.1"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
@@ -2976,7 +3170,7 @@ commander@2.9.0:
   dependencies:
     graceful-readlink ">= 1.0.0"
 
-commander@^2.12.1, commander@^2.18.0, commander@^2.20.0:
+commander@^2.11.0, commander@^2.12.1, commander@^2.18.0, commander@^2.20.0, commander@^2.7.1, commander@^2.9.0:
   version "2.20.0"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
   integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
@@ -2986,7 +3180,7 @@ commander@~2.19.0:
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
   integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
 
-common-tags@^1.4.0:
+common-tags@^1.4.0, common-tags@^1.5.1:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
   integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==
@@ -3072,6 +3266,14 @@ consolidate@^0.15.1:
   dependencies:
     bluebird "^3.1.1"
 
+constant-case@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46"
+  integrity sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=
+  dependencies:
+    snake-case "^2.1.0"
+    upper-case "^1.1.1"
+
 constantinople@^3.0.1, constantinople@^3.1.2:
   version "3.1.2"
   resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.2.tgz#d45ed724f57d3d10500017a7d3a889c1381ae647"
@@ -3147,7 +3349,7 @@ copy-webpack-plugin@^4.6.0:
     p-limit "^1.0.0"
     serialize-javascript "^1.4.0"
 
-core-js@^2.4.0, core-js@^2.6.5, core-js@^2.6.9:
+core-js@^2.4.0, core-js@^2.5.3, core-js@^2.5.7, core-js@^2.6.5, core-js@^2.6.9:
   version "2.6.9"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
   integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
@@ -3157,7 +3359,7 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
   integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
 
-cosmiconfig@^5.0.0:
+cosmiconfig@^5.0.0, cosmiconfig@^5.2.1:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
   integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
@@ -3205,6 +3407,29 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
     safe-buffer "^5.0.1"
     sha.js "^2.4.8"
 
+creato@^1.0.3:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/creato/-/creato-1.0.5.tgz#ef9a84f3584d880e19200ac3ad8d4b4df906c1ba"
+  integrity sha512-bneB5jF+I0XNe4d3E6PYszPRb+5S8B3UQ3hDlY6ZSkfEU34RKqCfbUodxwwJn8DhmPYiuefEqEGxvstXEwXuUA==
+  dependencies:
+    chalk "^2.4.1"
+    inquirer "^6.2.0"
+    mkdirp "^0.5.1"
+    ora "^3.0.0"
+    parse-github-url "^1.0.2"
+    request "^2.88.0"
+    tar "^4.4.7"
+    tmp "^0.1.0"
+    update-notifier "^2.5.0"
+
+cross-fetch@2.2.2:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.2.tgz#a47ff4f7fc712daba8f6a695a11c948440d45723"
+  integrity sha1-pH/09/xxLauo9qaVoRyUhEDUVyM=
+  dependencies:
+    node-fetch "2.1.2"
+    whatwg-fetch "2.0.4"
+
 cross-spawn@^3.0.0:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
@@ -3213,7 +3438,7 @@ cross-spawn@^3.0.0:
     lru-cache "^4.0.1"
     which "^1.2.9"
 
-cross-spawn@^5.0.1:
+cross-spawn@^5.0.1, cross-spawn@^5.1.0:
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
   integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
@@ -3443,6 +3668,18 @@ cssstyle@^1.1.1:
   dependencies:
     cssom "0.3.x"
 
+cucumber-html-reporter@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/cucumber-html-reporter/-/cucumber-html-reporter-3.0.4.tgz#1be0dee83f30a2f4719207859a5440ce082ffadd"
+  integrity sha512-uit68jymdI8Z6m+kJ5YnJPeHf5IdYXt2j52l5xLwgpcLBQRhCvr1peV9UODaCN5nLnRN9nqh1qaw4iNp1rTpvQ==
+  dependencies:
+    find "^0.2.7"
+    fs-extra "^3.0.1"
+    js-base64 "^2.3.2"
+    jsonfile "^3.0.0"
+    lodash "^4.17.2"
+    open "0.0.5"
+
 current-script-polyfill@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/current-script-polyfill/-/current-script-polyfill-1.0.0.tgz#f31cf7e4f3e218b0726e738ca92a02d3488ef615"
@@ -3528,7 +3765,7 @@ debug@4.1.0:
   dependencies:
     ms "^2.1.1"
 
-debug@^3.2.5, debug@^3.2.6:
+debug@^3.0.0, debug@^3.1.0, debug@^3.2.5, debug@^3.2.6:
   version "3.2.6"
   resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
   integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
@@ -3708,7 +3945,7 @@ detect-node@^2.0.4:
   resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
   integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
 
-diff@1.4.0:
+diff@1.4.0, diff@^1.3.2:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf"
   integrity sha1-fyjS657nsVqX79ic5j3P2qPMur8=
@@ -3734,6 +3971,14 @@ dir-glob@^2.0.0, dir-glob@^2.2.2:
   dependencies:
     path-type "^3.0.0"
 
+disparity@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/disparity/-/disparity-2.0.0.tgz#57ddacb47324ae5f58d2cc0da886db4ce9eeb718"
+  integrity sha1-V92stHMkrl9Y0swNqIbbTOnutxg=
+  dependencies:
+    ansi-styles "^2.0.1"
+    diff "^1.3.2"
+
 dns-equal@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@@ -3786,7 +4031,15 @@ dom-event-types@^1.0.0:
   resolved "https://registry.yarnpkg.com/dom-event-types/-/dom-event-types-1.0.0.tgz#5830a0a29e1bf837fe50a70cd80a597232813cae"
   integrity sha512-2G2Vwi2zXTHBGqXHsJ4+ak/iP0N8Ar+G8a7LiD2oup5o4sQWytwqqrZu/O6hIMV0KMID2PL69OhpshLO0n7UJQ==
 
-dom-serializer@0, dom-serializer@~0.1.1:
+dom-serializer@0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.1.tgz#13650c850daffea35d8b626a4cfc4d3a17643fdb"
+  integrity sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==
+  dependencies:
+    domelementtype "^2.0.1"
+    entities "^2.0.0"
+
+dom-serializer@~0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
   integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
@@ -3804,6 +4057,11 @@ domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
   resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
   integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
 
+domelementtype@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d"
+  integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==
+
 domexception@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
@@ -3834,6 +4092,13 @@ domutils@^1.5.1, domutils@^1.7.0:
     dom-serializer "0"
     domelementtype "1"
 
+dot-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-2.1.1.tgz#34dcf37f50a8e93c2b3bca8bb7fb9155c7da3bee"
+  integrity sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=
+  dependencies:
+    no-case "^2.2.0"
+
 dot-prop@^4.1.0, dot-prop@^4.1.1:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
@@ -3860,7 +4125,12 @@ dotenv-webpack@^1.7.0:
   dependencies:
     dotenv-defaults "^1.0.2"
 
-dotenv@^6.2.0:
+dotenv@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d"
+  integrity sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=
+
+dotenv@^6.1.0, dotenv@^6.2.0:
   version "6.2.0"
   resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064"
   integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==
@@ -3917,6 +4187,13 @@ ecc-jsbn@~0.1.1:
     jsbn "~0.1.0"
     safer-buffer "^2.1.0"
 
+ecdsa-sig-formatter@1.0.11:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
+  integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
+  dependencies:
+    safe-buffer "^5.0.1"
+
 ee-first@1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -3933,9 +4210,9 @@ ejs@^2.6.1:
   integrity sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q==
 
 electron-to-chromium@^1.3.191:
-  version "1.3.199"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.199.tgz#f9a62a74cda77854310a2abffde8b75591ea09a1"
-  integrity sha512-gachlDdHSK47s0N2e58GH9HMC6Z4ip0SfmYUa5iEbE50AKaOUXysaJnXMfKj0xB245jWbYcyFSH+th3rqsF8hA==
+  version "1.3.225"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.225.tgz#c6786475b5eb5f491ade01a78b82ba2c5bfdf72b"
+  integrity sha512-7W/L3jw7HYE+tUPbcVOGBmnSrlUmyZ/Uyg24QS7Vx0a9KodtNrN0r0Q/LyGHrcYMtw2rv7E49F/vTXwlV/fuaA==
 
 elliptic@^6.0.0:
   version "6.5.0"
@@ -3955,6 +4232,11 @@ emoji-regex@^7.0.1:
   resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
   integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
 
+emoji-regex@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+  integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
 emojis-list@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
@@ -3965,6 +4247,13 @@ encodeurl@~1.0.2:
   resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
   integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
 
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=
+  dependencies:
+    iconv-lite "~0.4.13"
+
 end-of-stream@^1.0.0, end-of-stream@^1.1.0:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
@@ -3986,7 +4275,12 @@ entities@^1.1.1, entities@~1.1.1:
   resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
   integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
 
-errno@^0.1.3, errno@~0.1.7:
+entities@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
+  integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==
+
+errno@^0.1.1, errno@^0.1.3, errno@~0.1.7:
   version "0.1.7"
   resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
   integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
@@ -4028,6 +4322,18 @@ es-to-primitive@^1.2.0:
     is-date-object "^1.0.1"
     is-symbol "^1.0.2"
 
+es6-promise@^4.0.3, es6-promise@^4.1.1:
+  version "4.2.8"
+  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
+  integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
+
+es6-promisify@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
+  integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
+  dependencies:
+    es6-promise "^4.0.3"
+
 escape-html@~1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@@ -4039,9 +4345,9 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
 
 escodegen@1.x.x, escodegen@^1.11.0:
-  version "1.11.1"
-  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.1.tgz#c485ff8d6b4cdb89e27f4a856e91f118401ca510"
-  integrity sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==
+  version "1.12.0"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.12.0.tgz#f763daf840af172bb3a2b6dd7219c0e17f7ff541"
+  integrity sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==
   dependencies:
     esprima "^3.1.3"
     estraverse "^4.2.0"
@@ -4050,7 +4356,7 @@ escodegen@1.x.x, escodegen@^1.11.0:
   optionalDependencies:
     source-map "~0.6.1"
 
-eslint-scope@^4.0.0:
+eslint-scope@^4.0.0, eslint-scope@^4.0.3:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
   integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
@@ -4165,9 +4471,9 @@ esutils@^1.1.6:
   integrity sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=
 
 esutils@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
-  integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+  integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
 
 etag@~1.8.1:
   version "1.8.1"
@@ -4256,7 +4562,32 @@ expand-brackets@^2.1.4:
     snapdragon "^0.8.1"
     to-regex "^3.0.1"
 
-express@^4.16.3, express@^4.17.1:
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+  integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+  dependencies:
+    homedir-polyfill "^1.0.1"
+
+express-request-proxy@^2.2.2:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/express-request-proxy/-/express-request-proxy-2.2.2.tgz#ebe8966e7ab47c97b59721f2714217a6389a2a76"
+  integrity sha512-0Dzn6LQG0ohd2S+zJVMhsntwcDakEzm/uKJSZxH7B66ZBvTsB5LU/HvfO1dHG+RRiKuCg0aWfUa66PljnDjEdw==
+  dependencies:
+    async "^2.6.1"
+    body-parser "^1.18.3"
+    camel-case "^3.0.0"
+    debug "^3.1.0"
+    lodash "^4.17.10"
+    lru-cache "^4.1.3"
+    path-to-regexp "^1.1.1"
+    request "^2.87.0"
+    simple-errors "^1.0.1"
+    through2 "^2.0.3"
+    type-is "^1.6.16"
+    url-join "4.0.0"
+
+express@^4.16.3, express@^4.16.4, express@^4.17.1:
   version "4.17.1"
   resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
   integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
@@ -4312,7 +4643,7 @@ extend@3, extend@~3.0.0, extend@~3.0.2:
   resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
   integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
 
-external-editor@^3.0.3:
+external-editor@^3.0.0, external-editor@^3.0.3:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
   integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
@@ -4355,6 +4686,11 @@ extsprintf@^1.2.0:
   resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
   integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
 
+fast-deep-equal@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
+  integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=
+
 fast-deep-equal@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
@@ -4427,6 +4763,13 @@ figures@^2.0.0:
   dependencies:
     escape-string-regexp "^1.0.5"
 
+figures@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-3.0.0.tgz#756275c964646163cc6f9197c7a0295dbfd04de9"
+  integrity sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==
+  dependencies:
+    escape-string-regexp "^1.0.5"
+
 file-entry-cache@^5.0.1:
   version "5.0.1"
   resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
@@ -4492,7 +4835,7 @@ find-cache-dir@^1.0.0:
     make-dir "^1.0.0"
     pkg-dir "^2.0.0"
 
-find-cache-dir@^2.0.0:
+find-cache-dir@^2.0.0, find-cache-dir@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
   integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==
@@ -4509,7 +4852,7 @@ find-up@^1.0.0:
     path-exists "^2.0.0"
     pinkie-promise "^2.0.0"
 
-find-up@^2.1.0:
+find-up@^2.0.0, find-up@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
   integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
@@ -4531,6 +4874,13 @@ find-yarn-workspace-root@^1.2.1:
     fs-extra "^4.0.3"
     micromatch "^3.1.4"
 
+find@^0.2.7:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/find/-/find-0.2.9.tgz#4b73f1ff9e56ad91b76e716407fe5ffe6554bb8c"
+  integrity sha1-S3Px/55WrZG3bnFkB/5f/mVUu4w=
+  dependencies:
+    traverse-chain "~0.1.0"
+
 flat-cache@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
@@ -4560,23 +4910,11 @@ follow-redirects@^1.0.0:
   dependencies:
     debug "^3.2.6"
 
-for-in@^0.1.3:
-  version "0.1.8"
-  resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
-  integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=
-
-for-in@^1.0.1, for-in@^1.0.2:
+for-in@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
   integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
 
-for-own@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
-  integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
-  dependencies:
-    for-in "^1.0.1"
-
 forever-agent@~0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@@ -4603,6 +4941,11 @@ form-data@~2.3.2:
     combined-stream "^1.0.6"
     mime-types "^2.1.12"
 
+format-util@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.3.tgz#032dca4a116262a12c43f4c3ec8566416c5b2d95"
+  integrity sha1-Ay3KShFiYqEsQ/TD7IVmQWxbLZU=
+
 format@^0.2.2:
   version "0.2.2"
   resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
@@ -4633,6 +4976,24 @@ from2@^2.1.0:
     inherits "^2.0.1"
     readable-stream "^2.0.0"
 
+fs-extra@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
+  integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==
+  dependencies:
+    graceful-fs "^4.1.2"
+    jsonfile "^4.0.0"
+    universalify "^0.1.0"
+
+fs-extra@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291"
+  integrity sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=
+  dependencies:
+    graceful-fs "^4.1.2"
+    jsonfile "^3.0.0"
+    universalify "^0.1.0"
+
 fs-extra@^4.0.2, fs-extra@^4.0.3:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
@@ -4642,7 +5003,7 @@ fs-extra@^4.0.2, fs-extra@^4.0.3:
     jsonfile "^4.0.0"
     universalify "^0.1.0"
 
-fs-extra@^7.0.1:
+fs-extra@^7.0.0, fs-extra@^7.0.1:
   version "7.0.1"
   resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
   integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
@@ -4854,6 +5215,26 @@ global-dirs@^0.1.0:
   dependencies:
     ini "^1.3.4"
 
+global-modules@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+  integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+  dependencies:
+    global-prefix "^1.0.1"
+    is-windows "^1.0.1"
+    resolve-dir "^1.0.0"
+
+global-prefix@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+  integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
+  dependencies:
+    expand-tilde "^2.0.2"
+    homedir-polyfill "^1.0.1"
+    ini "^1.3.4"
+    is-windows "^1.0.1"
+    which "^1.2.14"
+
 globals@^11.1.0, globals@^11.7.0:
   version "11.12.0"
   resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@@ -4923,15 +5304,168 @@ got@^6.7.1:
     url-parse-lax "^1.0.0"
 
 graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b"
-  integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.1.tgz#1c1f0c364882c868f5bff6512146328336a11b1d"
+  integrity sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==
 
 "graceful-readlink@>= 1.0.0":
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
   integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
 
+graphcool-json-schema@1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/graphcool-json-schema/-/graphcool-json-schema-1.2.1.tgz#6cefb6c8b50543615e6efa43bb54f9e3fbb281f3"
+  integrity sha1-bO+2yLUFQ2FebvpDu1T54/uygfM=
+
+graphcool-yml@0.4.15:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/graphcool-yml/-/graphcool-yml-0.4.15.tgz#9834a25daa62dc609558509a67396763ff81503b"
+  integrity sha512-ZVbRfVI8l21+1JQkcG0XuRam9mgiVUh9/PIcluzCZca2+lZQg/e1WCDXpwsC69i2ZdPcZwpOCLFKQMg5rnulCA==
+  dependencies:
+    ajv "^5.5.1"
+    bluebird "^3.5.1"
+    debug "^3.1.0"
+    dotenv "^4.0.0"
+    fs-extra "^4.0.3"
+    graphcool-json-schema "1.2.1"
+    isomorphic-fetch "^2.2.1"
+    js-yaml "^3.10.0"
+    json-stable-stringify "^1.0.1"
+    jsonwebtoken "^8.1.0"
+    lodash "^4.17.4"
+    replaceall "^0.1.6"
+    scuid "^1.0.2"
+    yaml-ast-parser "^0.0.40"
+
+graphql-cli-prepare@1.4.19:
+  version "1.4.19"
+  resolved "https://registry.yarnpkg.com/graphql-cli-prepare/-/graphql-cli-prepare-1.4.19.tgz#9df5d608ba42c4947d7ef24f9fc39e3df0c89301"
+  integrity sha512-PJFm9/DvfZwKz3h2Wyn/5Sr/sX35XsYzNO3olfm5V8qqueNIONI0g7sVqpF7wYdvhEtt/8YA9DjgrGclCbpMfA==
+  dependencies:
+    chalk "2.3.1"
+    fs-extra "5.0.0"
+    graphql-import "0.4.5"
+    graphql-static-binding "0.9.3"
+    lodash "4.17.5"
+
+graphql-cli@^3.0.12:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/graphql-cli/-/graphql-cli-3.0.12.tgz#c387b49f420410798db6d2739187d2af609e5fea"
+  integrity sha512-+6MxnbXHaAcpF574KTmpkXJmwXQmtP8YVaTY3IKBgqHzL5PMmTrrFgbLUbwDVJDZ5sSr/kMZgZFMiAczMYtykw==
+  dependencies:
+    apollo-codegen "^0.20.2"
+    chalk "^2.4.1"
+    command-exists "^1.2.8"
+    creato "^1.0.3"
+    cross-spawn "^6.0.5"
+    disparity "^2.0.0"
+    dotenv "^6.1.0"
+    express "^4.16.4"
+    express-request-proxy "^2.2.2"
+    graphql "^14.0.2"
+    graphql-cli-prepare "1.4.19"
+    graphql-config "2.2.1"
+    graphql-config-extension-graphcool "1.0.11"
+    graphql-config-extension-prisma "0.3.0"
+    graphql-playground-middleware-express "1.7.12"
+    graphql-schema-linter "0.2.1"
+    inquirer "6.2.0"
+    is-url-superb "2.0.0"
+    js-yaml "^3.12.0"
+    lodash "^4.17.11"
+    mkdirp "^0.5.1"
+    node-fetch "^2.3.0"
+    npm-paths "^1.0.0"
+    npm-run "4.1.2"
+    opn "^5.4.0"
+    ora "^3.0.0"
+    rimraf "2.6.3"
+    source-map-support "^0.5.9"
+    tmp-graphql-config-extension-openapi "^1.0.7"
+    update-notifier "^2.5.0"
+    yargs "12.0.5"
+
+graphql-config-extension-graphcool@1.0.11:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/graphql-config-extension-graphcool/-/graphql-config-extension-graphcool-1.0.11.tgz#749c156573d8956694a41c28461755b4592973f0"
+  integrity sha512-uNhyMqj30M4KLkD/gGEEr6cPuVX/jtm0C9O5Bj9V2jFhN5IdHXWJx+fC/p/xxh82iOuR8uibKNCXzwA7R6F6IA==
+  dependencies:
+    graphcool-yml "0.4.15"
+    graphql-config "2.2.1"
+
+graphql-config-extension-prisma@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/graphql-config-extension-prisma/-/graphql-config-extension-prisma-0.3.0.tgz#06758aadb7eb85b12dc1538807873d5890d4d4de"
+  integrity sha512-bOufkkog0cSfHJ9gVD3Wy+KHmkSTHWcFfPaV/NVpIvfJx15gU0/CzuC6lcTjioWmn+UGzYdoqmP7OrJAWT57sw==
+  dependencies:
+    graphql-config "2.2.1"
+    prisma-yml "1.26.6"
+
+graphql-config@2.2.1, graphql-config@^2.0.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-2.2.1.tgz#5fd0ec77ac7428ca5fb2026cf131be10151a0cb2"
+  integrity sha512-U8+1IAhw9m6WkZRRcyj8ZarK96R6lQBQ0an4lp76Ps9FyhOXENC5YQOxOFGm5CxPrX2rD0g3Je4zG5xdNJjwzQ==
+  dependencies:
+    graphql-import "^0.7.1"
+    graphql-request "^1.5.0"
+    js-yaml "^3.10.0"
+    lodash "^4.17.4"
+    minimatch "^3.0.4"
+
+graphql-import@0.4.5:
+  version "0.4.5"
+  resolved "https://registry.yarnpkg.com/graphql-import/-/graphql-import-0.4.5.tgz#e2f18c28d335733f46df8e0733d8deb1c6e2a645"
+  integrity sha512-G/+I08Qp6/QGTb9qapknCm3yPHV0ZL7wbaalWFpxsfR8ZhZoTBe//LsbsCKlbALQpcMegchpJhpTSKiJjhaVqQ==
+  dependencies:
+    lodash "^4.17.4"
+
+graphql-import@^0.7.1:
+  version "0.7.1"
+  resolved "https://registry.yarnpkg.com/graphql-import/-/graphql-import-0.7.1.tgz#4add8d91a5f752d764b0a4a7a461fcd93136f223"
+  integrity sha512-YpwpaPjRUVlw2SN3OPljpWbVRWAhMAyfSba5U47qGMOSsPLi2gYeJtngGpymjm9nk57RFWEpjqwh4+dpYuFAPw==
+  dependencies:
+    lodash "^4.17.4"
+    resolve-from "^4.0.0"
+
+graphql-playground-html@1.6.12:
+  version "1.6.12"
+  resolved "https://registry.yarnpkg.com/graphql-playground-html/-/graphql-playground-html-1.6.12.tgz#8b3b34ab6013e2c877f0ceaae478fafc8ca91b85"
+  integrity sha512-yOYFwwSMBL0MwufeL8bkrNDgRE7eF/kTHiwrqn9FiR9KLcNIl1xw9l9a+6yIRZM56JReQOHpbQFXTZn1IuSKRg==
+
+graphql-playground-middleware-express@1.7.12:
+  version "1.7.12"
+  resolved "https://registry.yarnpkg.com/graphql-playground-middleware-express/-/graphql-playground-middleware-express-1.7.12.tgz#de4b2402a02159b2125561fe38eb378b56cf6d99"
+  integrity sha512-17szgonnVSxWVrgblLRHHLjWnMUONfkULIwSunaMvYx8k5oG3yL86cyGCbHuDFUFkyr2swLhdfYl4mDfDXuvOA==
+  dependencies:
+    graphql-playground-html "1.6.12"
+
+graphql-request@^1.5.0:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-1.8.2.tgz#398d10ae15c585676741bde3fc01d5ca948f8fbe"
+  integrity sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==
+  dependencies:
+    cross-fetch "2.2.2"
+
+graphql-schema-linter@0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/graphql-schema-linter/-/graphql-schema-linter-0.2.1.tgz#f4231ff6def031a83fa86c66a4f2b688a78f505f"
+  integrity sha512-Z0rKFkxvIXqktkd/4luMYgBXWZeVCp8VJysOKz3RtbcpqbiIpdwtH0J678xOQ+hJLwEfrdCrhKNxxvRpt6mCSg==
+  dependencies:
+    chalk "^2.0.1"
+    columnify "^1.5.4"
+    commander "^2.11.0"
+    cosmiconfig "^5.2.1"
+    glob "^7.1.2"
+    graphql "^14.0.0"
+
+graphql-static-binding@0.9.3:
+  version "0.9.3"
+  resolved "https://registry.yarnpkg.com/graphql-static-binding/-/graphql-static-binding-0.9.3.tgz#67a51ed2e720edda5a250898af037ebf9dac57cf"
+  integrity sha512-C8+EqwNCiQxUhbrWEokxN16oINAkhIDBzEpKHXeatBRaAyMczXm0J6HMaMSKOuQmk7P1PbDHIVW3FVZwXF2WJQ==
+  dependencies:
+    cucumber-html-reporter "^3.0.4"
+
 graphql-tag@^2.10.1:
   version "2.10.1"
   resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.1.tgz#10aa41f1cd8fae5373eaf11f1f67260a3cad5e02"
@@ -4944,7 +5478,14 @@ graphql@0.11.3:
   dependencies:
     iterall "^1.1.0"
 
-graphql@^14.2.1:
+graphql@^0.13.1:
+  version "0.13.2"
+  resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.13.2.tgz#4c740ae3c222823e7004096f832e7b93b2108270"
+  integrity sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==
+  dependencies:
+    iterall "^1.2.1"
+
+graphql@^14.0.0, graphql@^14.0.2, graphql@^14.2.1:
   version "14.4.2"
   resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.4.2.tgz#553a7d546d524663eda49ed6df77577be3203ae3"
   integrity sha512-6uQadiRgnpnSS56hdZUSvFrVcQ6OF9y6wkxJfKquFtHlnl7+KSuWwSJsdwiK1vybm1HgcdbpGkCpvhvsVQ0UZQ==
@@ -5083,15 +5624,23 @@ he@1.2.x, he@^1.1.0:
   resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
   integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
 
+header-case@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d"
+  integrity sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.1.3"
+
 hex-color-regex@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
   integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
 
 highlight.js@^9.6.0, highlight.js@~9.15.0:
-  version "9.15.8"
-  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.8.tgz#f344fda123f36f1a65490e932cf90569e4999971"
-  integrity sha512-RrapkKQWwE+wKdF73VsOa2RQdIoO3mxwJ4P8mhbI6KYJUraUHRKM5w5zQQKXNk0xNL4UVRdulV9SBJcmzJNzVA==
+  version "9.15.9"
+  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.9.tgz#865257da1dbb4a58c4552d46c4b3854f77f0e6d5"
+  integrity sha512-M0zZvfLr5p0keDMCAhNBp03XJbKBxUx5AfyfufMdFMEP4N/Xj6dh0IqC75ys7BAzceR34NgcvXjupRVaHBPPVQ==
 
 hmac-drbg@^1.0.0:
   version "1.0.1"
@@ -5107,15 +5656,22 @@ hoek@4.x.x:
   resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
   integrity sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==
 
+homedir-polyfill@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+  integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+  dependencies:
+    parse-passwd "^1.0.0"
+
 hoopy@^0.1.4:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
   integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==
 
 hosted-git-info@^2.1.4:
-  version "2.7.1"
-  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
-  integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
+  version "2.8.4"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546"
+  integrity sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==
 
 hpack.js@^2.1.6:
   version "2.1.6"
@@ -5248,6 +5804,14 @@ http-proxy-agent@1:
     debug "2"
     extend "3"
 
+http-proxy-agent@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
+  integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==
+  dependencies:
+    agent-base "4"
+    debug "3.1.0"
+
 http-proxy-middleware@^0.19.1:
   version "0.19.1"
   resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a"
@@ -5290,7 +5854,15 @@ https-proxy-agent@1:
     debug "2"
     extend "3"
 
-iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
+https-proxy-agent@^2.2.1:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz#271ea8e90f836ac9f119daccd39c19ff7dfb0793"
+  integrity sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==
+  dependencies:
+    agent-base "^4.3.0"
+    debug "^3.1.0"
+
+iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
   version "0.4.24"
   resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
   integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@@ -5401,6 +5973,16 @@ indexes-of@^1.0.1:
   resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
   integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
 
+infer-owner@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
+  integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
+
+inflected@^2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inflected/-/inflected-2.0.4.tgz#323770961ccbe992a98ea930512e9a82d3d3ef77"
+  integrity sha512-HQPzFLTTUvwfeUH6RAGjD8cHS069mBqXG5n4qaxX7sJXBhVQrsGgF+0ZJGkSuN6a8pcUWB/GXStta11kKi/WvA==
+
 inflight@^1.0.4:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -5429,22 +6011,41 @@ ini@^1.3.4, ini@~1.3.0:
   resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
   integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
 
-inquirer@^6.4.1:
-  version "6.5.0"
-  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42"
-  integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==
+inquirer@6.2.0:
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8"
+  integrity sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==
   dependencies:
-    ansi-escapes "^3.2.0"
-    chalk "^2.4.2"
+    ansi-escapes "^3.0.0"
+    chalk "^2.0.0"
     cli-cursor "^2.1.0"
     cli-width "^2.0.0"
-    external-editor "^3.0.3"
+    external-editor "^3.0.0"
     figures "^2.0.0"
-    lodash "^4.17.12"
+    lodash "^4.17.10"
     mute-stream "0.0.7"
     run-async "^2.2.0"
-    rxjs "^6.4.0"
+    rxjs "^6.1.0"
     string-width "^2.1.0"
+    strip-ansi "^4.0.0"
+    through "^2.3.6"
+
+inquirer@^6.2.0, inquirer@^6.4.1:
+  version "6.5.1"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.1.tgz#8bfb7a5ac02dac6ff641ac4c5ff17da112fcdb42"
+  integrity sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw==
+  dependencies:
+    ansi-escapes "^4.2.1"
+    chalk "^2.4.2"
+    cli-cursor "^3.1.0"
+    cli-width "^2.0.0"
+    external-editor "^3.0.3"
+    figures "^3.0.0"
+    lodash "^4.17.15"
+    mute-stream "0.0.8"
+    run-async "^2.2.0"
+    rxjs "^6.4.0"
+    string-width "^4.1.0"
     strip-ansi "^5.1.0"
     through "^2.3.6"
 
@@ -5483,6 +6084,11 @@ invert-kv@^2.0.0:
   resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
   integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
 
+ip-regex@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-1.0.3.tgz#dc589076f659f419c222039a33316f1c7387effd"
+  integrity sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=
+
 ip-regex@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@@ -5513,6 +6119,11 @@ is-absolute-url@^2.0.0:
   resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
   integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=
 
+is-absolute-url@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.0.tgz#eb21d69df2ed8ef72a3e6f243e216563036a0913"
+  integrity sha512-3OkP8XrM2Xq4/IxsJnClfMp3OaM3TAatLPLKPeWcxLBTrpe6hihwtX+XZfJTcXg/FTRi4qjy0y/C5qiyNxY24g==
+
 is-accessor-descriptor@^0.1.6:
   version "0.1.6"
   resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
@@ -5666,6 +6277,11 @@ is-fullwidth-code-point@^2.0.0:
   resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
   integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
 
+is-fullwidth-code-point@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+  integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
 is-glob@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
@@ -5688,6 +6304,13 @@ is-installed-globally@^0.1.0:
     global-dirs "^0.1.0"
     is-path-inside "^1.0.0"
 
+is-lower-case@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-1.1.3.tgz#7e147be4768dc466db3bfb21cc60b31e6ad69393"
+  integrity sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=
+  dependencies:
+    lower-case "^1.1.0"
+
 is-npm@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
@@ -5787,7 +6410,7 @@ is-retry-allowed@^1.0.0:
   resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
   integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=
 
-is-stream@^1.0.0, is-stream@^1.1.0:
+is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
   integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
@@ -5811,6 +6434,20 @@ is-typedarray@~1.0.0:
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
   integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
 
+is-upper-case@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-1.1.2.tgz#8d0b1fa7e7933a1e58483600ec7d9661cbaf756f"
+  integrity sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=
+  dependencies:
+    upper-case "^1.1.0"
+
+is-url-superb@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-url-superb/-/is-url-superb-2.0.0.tgz#b728a18cf692e4d16da6b94c7408a811db0d0492"
+  integrity sha1-tyihjPaS5NFtprlMdAioEdsNBJI=
+  dependencies:
+    url-regex "^3.0.0"
+
 is-url@^1.2.2:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
@@ -5821,7 +6458,7 @@ is-utf8@^0.2.0:
   resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
   integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
 
-is-windows@^1.0.2:
+is-windows@^1.0.1, is-windows@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
   integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
@@ -5874,12 +6511,20 @@ isobject@^3.0.0, isobject@^3.0.1:
   resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
   integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
 
+isomorphic-fetch@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
 isstream@~0.1.2:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
   integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
 
-iterall@^1.1.0, iterall@^1.2.2:
+iterall@^1.1.0, iterall@^1.2.1, iterall@^1.2.2:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"
   integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==
@@ -5898,7 +6543,7 @@ joi@^11.1.1:
     isemail "3.x.x"
     topo "2.x.x"
 
-js-base64@^2.1.8:
+js-base64@^2.1.8, js-base64@^2.3.2:
   version "2.5.1"
   resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
   integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
@@ -5935,7 +6580,7 @@ js-tokens@^3.0.2:
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
   integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
 
-js-yaml@^3.13.1:
+js-yaml@^3.10.0, js-yaml@^3.12.0, js-yaml@^3.13.1, js-yaml@^3.8.4, js-yaml@^3.9.1:
   version "3.13.1"
   resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
   integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
@@ -6000,6 +6645,23 @@ json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
   resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
   integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
 
+json-schema-ref-parser@^3.1.2:
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/json-schema-ref-parser/-/json-schema-ref-parser-3.3.1.tgz#86e751b8099357bf601a7cfe42d10123ee906a32"
+  integrity sha512-stQTMhec2R/p2L9dH4XXRlpNCP0mY8QrLd/9Kl+8SHJQmwHtE1nDfXH4wbsSM+GkJMl8t92yZbI0OIol432CIQ==
+  dependencies:
+    call-me-maybe "^1.0.1"
+    debug "^3.0.0"
+    es6-promise "^4.1.1"
+    js-yaml "^3.9.1"
+    ono "^4.0.2"
+    z-schema "^3.18.2"
+
+json-schema-traverse@^0.3.0:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
+  integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=
+
 json-schema-traverse@^0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@@ -6056,6 +6718,13 @@ json5@^2.1.0:
   dependencies:
     minimist "^1.2.0"
 
+jsonfile@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
+  integrity sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=
+  optionalDependencies:
+    graceful-fs "^4.1.6"
+
 jsonfile@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
@@ -6068,6 +6737,22 @@ jsonify@~0.0.0:
   resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
   integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
 
+jsonwebtoken@^8.1.0:
+  version "8.5.1"
+  resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
+  integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==
+  dependencies:
+    jws "^3.2.2"
+    lodash.includes "^4.3.0"
+    lodash.isboolean "^3.0.3"
+    lodash.isinteger "^4.0.4"
+    lodash.isnumber "^3.0.3"
+    lodash.isplainobject "^4.0.6"
+    lodash.isstring "^4.0.1"
+    lodash.once "^4.0.0"
+    ms "^2.1.1"
+    semver "^5.6.0"
+
 jsprim@^1.2.2:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@@ -6086,6 +6771,23 @@ jstransformer@1.0.0:
     is-promise "^2.0.0"
     promise "^7.0.1"
 
+jwa@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
+  integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
+  dependencies:
+    buffer-equal-constant-time "1.0.1"
+    ecdsa-sig-formatter "1.0.11"
+    safe-buffer "^5.0.1"
+
+jws@^3.2.2:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
+  integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
+  dependencies:
+    jwa "^1.4.1"
+    safe-buffer "^5.0.1"
+
 killable@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@@ -6197,7 +6899,17 @@ load-json-file@^1.0.0:
     pinkie-promise "^2.0.0"
     strip-bom "^2.0.0"
 
-loader-runner@^2.3.0, loader-runner@^2.3.1:
+load-json-file@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
+  integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    strip-bom "^3.0.0"
+
+loader-runner@^2.3.0, loader-runner@^2.3.1, loader-runner@^2.4.0:
   version "2.4.0"
   resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
   integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
@@ -6347,6 +7059,16 @@ lodash.defaultsdeep@^4.6.1:
   resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6"
   integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==
 
+lodash.get@^4.0.0:
+  version "4.4.2"
+  resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
+  integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
+
+lodash.includes@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
+  integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=
+
 lodash.isarguments@^3.0.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
@@ -6357,11 +7079,36 @@ lodash.isarray@^3.0.0:
   resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
   integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=
 
-lodash.isplainobject@^4.0.0:
+lodash.isboolean@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
+  integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=
+
+lodash.isequal@^4.0.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+  integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
+
+lodash.isinteger@^4.0.4:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
+  integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=
+
+lodash.isnumber@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
+  integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=
+
+lodash.isplainobject@^4.0.0, lodash.isplainobject@^4.0.6:
   version "4.0.6"
   resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
   integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
 
+lodash.isstring@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
+  integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
+
 lodash.kebabcase@^4.1.1:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
@@ -6396,6 +7143,11 @@ lodash.mergewith@^4.0.0:
   resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
   integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
 
+lodash.once@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
+  integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
+
 lodash.rest@^4.0.0:
   version "4.0.5"
   resolved "https://registry.yarnpkg.com/lodash.rest/-/lodash.rest-4.0.5.tgz#954ef75049262038c96d1fc98b28fdaf9f0772aa"
@@ -6406,11 +7158,6 @@ lodash.sortby@^4.7.0:
   resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
   integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
 
-lodash.tail@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
-  integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=
-
 lodash.template@^4.4.0:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
@@ -6441,7 +7188,12 @@ lodash.uniq@^4.5.0:
   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
   integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
 
-lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10:
+lodash@4.17.5:
+  version "4.17.5"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
+  integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==
+
+lodash@^4.0.0, lodash@^4.15.0, lodash@^4.16.4, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.10:
   version "4.17.15"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
   integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -6478,7 +7230,14 @@ loud-rejection@^1.0.0:
     currently-unhandled "^0.4.1"
     signal-exit "^3.0.0"
 
-lower-case@^1.1.1:
+lower-case-first@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1"
+  integrity sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=
+  dependencies:
+    lower-case "^1.1.2"
+
+lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
   integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
@@ -6496,7 +7255,7 @@ lowlight@^1.12.1:
     fault "^1.0.2"
     highlight.js "~9.15.0"
 
-lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2:
+lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3:
   version "4.1.5"
   resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
   integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
@@ -6637,9 +7396,9 @@ merge-source-map@^1.1.0:
     source-map "^0.6.1"
 
 merge2@^1.2.3:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
-  integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.4.tgz#c9269589e6885a60cf80605d9522d4b67ca646e3"
+  integrity sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A==
 
 methods@~1.1.2:
   version "1.1.2"
@@ -6700,7 +7459,7 @@ mimic-fn@^1.0.0:
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
   integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
 
-mimic-fn@^2.0.0:
+mimic-fn@^2.0.0, mimic-fn@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
   integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
@@ -6809,14 +7568,6 @@ mixin-deep@^1.2.0:
     for-in "^1.0.2"
     is-extendable "^1.0.1"
 
-mixin-object@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
-  integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=
-  dependencies:
-    for-in "^0.1.3"
-    is-extendable "^0.1.1"
-
 mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
   version "0.5.1"
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@@ -6936,6 +7687,11 @@ mute-stream@0.0.7:
   resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
   integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
 
+mute-stream@0.0.8:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
+  integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
+
 mz@^2.4.0:
   version "2.7.0"
   resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
@@ -6986,7 +7742,7 @@ negotiator@0.6.2:
   resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
   integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
 
-neo-async@^2.5.0, neo-async@^2.6.0:
+neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1:
   version "2.6.1"
   resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
   integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
@@ -7022,13 +7778,31 @@ nightwatch@^0.9.21:
     proxy-agent "2.0.0"
     q "1.4.1"
 
-no-case@^2.2.0:
+no-case@^2.2.0, no-case@^2.3.2:
   version "2.3.2"
   resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
   integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
   dependencies:
     lower-case "^1.1.1"
 
+node-fetch@2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5"
+  integrity sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=
+
+node-fetch@^1.0.1, node-fetch@^1.7.3:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
+  integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-fetch@^2.3.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
+  integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+
 node-forge@0.7.5:
   version "0.7.5"
   resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
@@ -7061,7 +7835,7 @@ node-ipc@^9.1.1:
     js-message "1.0.5"
     js-queue "2.0.0"
 
-node-libs-browser@^2.0.0:
+node-libs-browser@^2.0.0, node-libs-browser@^2.2.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
   integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
@@ -7107,12 +7881,17 @@ node-pre-gyp@^0.12.0:
     tar "^4"
 
 node-releases@^1.1.25:
-  version "1.1.25"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3"
-  integrity sha512-fI5BXuk83lKEoZDdH3gRhtsNgh05/wZacuXkgbiYkceE7+QIMXOg98n9ZV7mz27B+kFHnqHcUpscZZlGRSmTpQ==
+  version "1.1.27"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.27.tgz#b19ec8add2afe9a826a99dceccc516104c1edaf4"
+  integrity sha512-9iXUqHKSGo6ph/tdXVbHFbhRVQln4ZDTIBJCzsa90HimnBYc5jw8RWYt4wBYFHehGyC3koIz5O4mb2fHrbPOuA==
   dependencies:
     semver "^5.3.0"
 
+node-request-by-swagger@^1.0.6:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/node-request-by-swagger/-/node-request-by-swagger-1.1.4.tgz#909a057bd4dffdf5245cb713f5543a9c56eea94d"
+  integrity sha512-hwaTaFPUwNKns5qXwGJpLQM3Z5zRluYeAxpYy1L8fWmWdT/DjLmsnW8/oGlSN8Vo4R28c2znfUoBUiB/RlPptw==
+
 node-sass@^4.11.0:
   version "4.12.0"
   resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
@@ -7215,6 +7994,21 @@ npm-packlist@^1.1.6:
     ignore-walk "^3.0.1"
     npm-bundled "^1.0.1"
 
+npm-path@^2.0.2, npm-path@^2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64"
+  integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==
+  dependencies:
+    which "^1.2.10"
+
+npm-paths@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/npm-paths/-/npm-paths-1.0.0.tgz#6e66ffc8887d27db71f9e8c4edd17e11c78a1c73"
+  integrity sha512-COlxSO5PK9UvZXIa7/sqJDZOlffWFx9+CKJJWkdbhUJMBwcf9sof2jxt4uiVsl+nY3sy0/XFGl4iGr8GoKfiXA==
+  dependencies:
+    global-modules "^1.0.0"
+    is-windows "^1.0.1"
+
 npm-run-path@^2.0.0:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
@@ -7222,6 +8016,27 @@ npm-run-path@^2.0.0:
   dependencies:
     path-key "^2.0.0"
 
+npm-run@4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/npm-run/-/npm-run-4.1.2.tgz#1030e1ec56908c89fcc3fa366d03a2c2ba98eb99"
+  integrity sha1-EDDh7FaQjIn8w/o2bQOiwrqY65k=
+  dependencies:
+    cross-spawn "^5.1.0"
+    minimist "^1.2.0"
+    npm-path "^2.0.3"
+    npm-which "^3.0.1"
+    serializerr "^1.0.3"
+    sync-exec "^0.6.2"
+
+npm-which@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa"
+  integrity sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=
+  dependencies:
+    commander "^2.9.0"
+    npm-path "^2.0.2"
+    which "^1.2.10"
+
 "npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@@ -7351,6 +8166,25 @@ onetime@^2.0.0:
   dependencies:
     mimic-fn "^1.0.0"
 
+onetime@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5"
+  integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==
+  dependencies:
+    mimic-fn "^2.1.0"
+
+ono@^4.0.2:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/ono/-/ono-4.0.11.tgz#c7f4209b3e396e8a44ef43b9cedc7f5d791d221d"
+  integrity sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==
+  dependencies:
+    format-util "^1.0.3"
+
+open@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
+  integrity sha1-QsPhjslUZra/DcQvOilFw/DK2Pw=
+
 open@^6.3.0:
   version "6.4.0"
   resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9"
@@ -7363,17 +8197,17 @@ opener@^1.5.1:
   resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
   integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
 
-opn@^5.5.0:
+opn@^5.4.0, opn@^5.5.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
   integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==
   dependencies:
     is-wsl "^1.1.0"
 
-optimism@^0.9.0:
-  version "0.9.6"
-  resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.9.6.tgz#5621195486b294c3bfc518d17ac47767234b029f"
-  integrity sha512-bWr/ZP32UgFCQAoSkz33XctHwpq2via2sBvGvO5JIlrU8gaiM0LvoKj3QMle9LWdSKlzKik8XGSerzsdfYLNxA==
+optimism@^0.10.0:
+  version "0.10.2"
+  resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.10.2.tgz#626b6fd28b0923de98ecb36a3fd2d3d4e5632dd9"
+  integrity sha512-zPfBIxFFWMmQboM9+Z4MSJqc1PXp82v1PFq/GfQaufI69mHKlup7ykGNnfuGIGssXJQkmhSodQ/k9EWwjd8O8A==
   dependencies:
     "@wry/context" "^0.4.0"
 
@@ -7397,7 +8231,7 @@ optionator@^0.8.1, optionator@^0.8.2:
     type-check "~0.3.2"
     wordwrap "~1.0.0"
 
-ora@^3.4.0:
+ora@^3.0.0, ora@^3.4.0:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318"
   integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==
@@ -7589,7 +8423,7 @@ parallel-transform@^1.1.0:
     inherits "^2.0.3"
     readable-stream "^2.1.5"
 
-param-case@2.1.x:
+param-case@2.1.x, param-case@^2.1.0:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
   integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
@@ -7615,6 +8449,11 @@ parse-asn1@^5.0.0:
     pbkdf2 "^3.0.3"
     safe-buffer "^5.1.1"
 
+parse-github-url@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/parse-github-url/-/parse-github-url-1.0.2.tgz#242d3b65cbcdda14bb50439e3242acf6971db395"
+  integrity sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==
+
 parse-json@^2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
@@ -7640,6 +8479,11 @@ parse-json@^5.0.0:
     json-parse-better-errors "^1.0.1"
     lines-and-columns "^1.1.6"
 
+parse-passwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+  integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+
 parse5@5.1.0:
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
@@ -7662,6 +8506,14 @@ parseurl@~1.3.2, parseurl@~1.3.3:
   resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
   integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
 
+pascal-case@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e"
+  integrity sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=
+  dependencies:
+    camel-case "^3.0.0"
+    upper-case-first "^1.1.0"
+
 pascalcase@^0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
@@ -7691,6 +8543,13 @@ path-browserify@0.0.1:
   resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
   integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
 
+path-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
+  integrity sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=
+  dependencies:
+    no-case "^2.2.0"
+
 path-dirname@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
@@ -7733,6 +8592,13 @@ path-to-regexp@0.1.7:
   resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
   integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
 
+path-to-regexp@^1.1.1:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
+  integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=
+  dependencies:
+    isarray "0.0.1"
+
 path-type@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
@@ -7742,6 +8608,13 @@ path-type@^1.0.0:
     pify "^2.0.0"
     pinkie-promise "^2.0.0"
 
+path-type@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
+  integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
+  dependencies:
+    pify "^2.0.0"
+
 path-type@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -7838,7 +8711,7 @@ popper.js@^1.14.7:
   resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2"
   integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==
 
-portfinder@^1.0.20:
+portfinder@^1.0.20, portfinder@^1.0.21:
   version "1.0.21"
   resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.21.tgz#60e1397b95ac170749db70034ece306b9a27e324"
   integrity sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA==
@@ -8173,9 +9046,9 @@ postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0, postcss-value-parser@^
   integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
 
 postcss-value-parser@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz#99a983d365f7b2ad8d0f9b8c3094926eab4b936d"
-  integrity sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ==
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9"
+  integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==
 
 postcss@^6.0.1, postcss@^6.0.20, postcss@^6.0.23:
   version "6.0.23"
@@ -8233,6 +9106,35 @@ pretty-error@^2.0.2:
     renderkid "^2.0.1"
     utila "~0.4"
 
+prisma-json-schema@0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/prisma-json-schema/-/prisma-json-schema-0.1.3.tgz#6c302db8f464f8b92e8694d3f7dd3f41ac9afcbe"
+  integrity sha512-XZrf2080oR81mY8/OC8al68HiwBm0nXlFE727JIia0ZbNqwuV4MyRYk6E0+OIa6/9KEYxZrcAmoBs3EW1cCvnA==
+
+prisma-yml@1.26.6:
+  version "1.26.6"
+  resolved "https://registry.yarnpkg.com/prisma-yml/-/prisma-yml-1.26.6.tgz#e91b63c6cfb49bcb0ae09b76d8524f58fc0668a9"
+  integrity sha512-dWBTeQbyWr/4d97ZKjxFPvIHytnNlBsNzgsJC1eew3qoZ9A8vtRIFhsnPiD3kYIf67w56i2QO2O5Infe2FzMww==
+  dependencies:
+    ajv "5"
+    bluebird "^3.5.1"
+    chalk "^2.3.0"
+    debug "^3.1.0"
+    dotenv "^4.0.0"
+    fs-extra "^7.0.0"
+    graphql-request "^1.5.0"
+    http-proxy-agent "^2.1.0"
+    https-proxy-agent "^2.2.1"
+    isomorphic-fetch "^2.2.1"
+    js-yaml "^3.10.0"
+    json-stable-stringify "^1.0.1"
+    jsonwebtoken "^8.1.0"
+    lodash "^4.17.4"
+    prisma-json-schema "0.1.3"
+    replaceall "^0.1.6"
+    scuid "^1.0.2"
+    yaml-ast-parser "^0.0.40"
+
 private@^0.1.6:
   version "0.1.8"
   resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
@@ -8341,17 +9243,17 @@ prosemirror-schema-list@^1.0.3:
     prosemirror-transform "^1.0.0"
 
 prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.2.3:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.2.3.tgz#b61e88e55336a4e5be088c0d21ac05f18cdd3dcd"
-  integrity sha512-TNFw98jHLcU7JXViozcDHxzIWQj7WfGqTAB05RCrkkUuIleKekW9PbhQGXRZdlSPFkViPlLy/emh+5HtjH1Yzg==
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.2.4.tgz#aab932ebb33a0f27c256abce6fc20da8ca77ad5e"
+  integrity sha512-ViXpXond3BbSL12ENARQGq3Y8igwFMbTcy96xUNK8kfIcfQRlYlgYrBPXIkHC5+QZtbPrYlpuJ2+QyeSlSX9Cw==
   dependencies:
     prosemirror-model "^1.0.0"
     prosemirror-transform "^1.0.0"
 
-prosemirror-tables@^0.8.1:
-  version "0.8.1"
-  resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-0.8.1.tgz#ea99ad4effec99dd4e2fdb0b33cce4d2547eed83"
-  integrity sha512-6eY8I+NkyrXAQ1gmYkKo7XDLZaj0iGutdc/zT0+VMY15IzgBINwcRP62+miaCTuneLTKufMYzfUB37NjGJaetw==
+prosemirror-tables@^0.9.1:
+  version "0.9.1"
+  resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-0.9.1.tgz#1669100ee9f64b0c269824dcd1c0584c66075acb"
+  integrity sha512-n5h2OvlnQGsW1ToT1WOIlemV/3PDw4miUQoHEpawOk2oDhi46czKdzEg/rq3z0f/aZ3CwoyxviuqAZChBILC4A==
   dependencies:
     prosemirror-keymap "^1.0.0"
     prosemirror-model "^1.0.0"
@@ -8366,20 +9268,25 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor
   dependencies:
     prosemirror-model "^1.0.0"
 
-prosemirror-utils@^0.9.4:
-  version "0.9.4"
-  resolved "https://registry.yarnpkg.com/prosemirror-utils/-/prosemirror-utils-0.9.4.tgz#9de3c638040070cf312a5adcf76fd58cf94e7a7d"
-  integrity sha512-6R3AqS+g3ohnWvgWb/eE1v+Kl1Hp0q/FXflJk8/tHEzXHCxjPXJrU8onf458kANSbB+g8yaCRjd7+3/Gne1LKA==
+prosemirror-utils@^0.9.6:
+  version "0.9.6"
+  resolved "https://registry.yarnpkg.com/prosemirror-utils/-/prosemirror-utils-0.9.6.tgz#3d97bd85897e3b535555867dc95a51399116a973"
+  integrity sha512-UC+j9hQQ1POYfMc5p7UFxBTptRiGPR7Kkmbl3jVvU8VgQbkI89tR/GK+3QYC8n+VvBZrtAoCrJItNhWSxX3slA==
 
-prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.9.12:
-  version "1.9.12"
-  resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.9.12.tgz#d0afc22387080ab2f6e0c44bca97486f3af6fbb0"
-  integrity sha512-og0JxRtce/hsg+61aPgCasfQtkqWYKuWmunU8H4+194AUpaYWg4ZmLNY9qWjfN7XKXoEtV4vPOUJ5RrYVijGjw==
+prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.9.13:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.10.0.tgz#7de5de75f0c90f8b9f09d09ed4467554d59adddb"
+  integrity sha512-STHw0xHfk+XPMqMLTKykRL1qEMtO+n1GWINBl94IPIq82AmWO1Ors4wVw93HKo/oIadWRrP/7faNJKh1UVLrTg==
   dependencies:
     prosemirror-model "^1.1.0"
     prosemirror-state "^1.0.0"
     prosemirror-transform "^1.1.0"
 
+protochain@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/protochain/-/protochain-1.0.5.tgz#991c407e99de264aadf8f81504b5e7faf7bfa260"
+  integrity sha1-mRxAfpneJkqt+PgVBLXn+ve/omA=
+
 proxy-addr@~2.0.5:
   version "2.0.5"
   resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
@@ -8413,9 +9320,9 @@ pseudomap@^1.0.2:
   integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
 
 psl@^1.1.24, psl@^1.1.28:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6"
-  integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/psl/-/psl-1.3.0.tgz#e1ebf6a3b5564fa8376f3da2275da76d875ca1bd"
+  integrity sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==
 
 public-encrypt@^4.0.0:
   version "4.0.3"
@@ -8676,6 +9583,14 @@ read-pkg-up@^1.0.1:
     find-up "^1.0.0"
     read-pkg "^1.0.0"
 
+read-pkg-up@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
+  integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
+  dependencies:
+    find-up "^2.0.0"
+    read-pkg "^2.0.0"
+
 read-pkg@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
@@ -8685,6 +9600,15 @@ read-pkg@^1.0.0:
     normalize-package-data "^2.3.2"
     path-type "^1.0.0"
 
+read-pkg@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
+  integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
+  dependencies:
+    load-json-file "^2.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^2.0.0"
+
 read-pkg@^5.0.0:
   version "5.2.0"
   resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
@@ -8749,7 +9673,7 @@ reflect-metadata@^0.1.12:
   resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
   integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
 
-regenerate-unicode-properties@^8.0.2:
+regenerate-unicode-properties@^8.1.0:
   version "8.1.0"
   resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
   integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
@@ -8806,12 +9730,12 @@ regexpu-core@^1.0.0:
     regjsparser "^0.1.4"
 
 regexpu-core@^4.5.4:
-  version "4.5.4"
-  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
-  integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==
+  version "4.5.5"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.5.tgz#aaffe61c2af58269b3e516b61a73790376326411"
+  integrity sha512-FpI67+ky9J+cDizQUJlIlNZFKual/lUkFr1AG6zOCpwZ9cLrg8UUVakyUQJD7fCDIe9Z2nwTQJNPyonatNmDFQ==
   dependencies:
     regenerate "^1.4.0"
-    regenerate-unicode-properties "^8.0.2"
+    regenerate-unicode-properties "^8.1.0"
     regjsgen "^0.5.0"
     regjsparser "^0.6.0"
     unicode-match-property-ecmascript "^1.0.4"
@@ -8899,6 +9823,11 @@ repeating@^2.0.0:
   dependencies:
     is-finite "^1.0.0"
 
+replaceall@^0.1.6:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/replaceall/-/replaceall-0.1.6.tgz#81d81ac7aeb72d7f5c4942adf2697a3220688d8e"
+  integrity sha1-gdgax663LX9cSUKt8ml6MiBojY4=
+
 request-promise-core@1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.2.tgz#339f6aababcafdb31c799ff158700336301d3346"
@@ -8915,7 +9844,17 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.7:
     stealthy-require "^1.1.1"
     tough-cookie "^2.3.3"
 
-request@^2.87.0, request@^2.88.0:
+request-promise@^4.1.1:
+  version "4.2.4"
+  resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.4.tgz#1c5ed0d71441e38ad58c7ce4ea4ea5b06d54b310"
+  integrity sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==
+  dependencies:
+    bluebird "^3.5.0"
+    request-promise-core "1.1.2"
+    stealthy-require "^1.1.1"
+    tough-cookie "^2.3.3"
+
+request@^2.75.0, request@^2.87.0, request@^2.88.0:
   version "2.88.0"
   resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
   integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
@@ -8973,6 +9912,14 @@ resolve-cwd@^2.0.0:
   dependencies:
     resolve-from "^3.0.0"
 
+resolve-dir@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+  integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
+  dependencies:
+    expand-tilde "^2.0.0"
+    global-modules "^1.0.0"
+
 resolve-from@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
@@ -8989,9 +9936,9 @@ resolve-url@^0.2.1:
   integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
 
 resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.8.1:
-  version "1.11.1"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e"
-  integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==
+  version "1.12.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6"
+  integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==
   dependencies:
     path-parse "^1.0.6"
 
@@ -9003,6 +9950,14 @@ restore-cursor@^2.0.0:
     onetime "^2.0.0"
     signal-exit "^3.0.2"
 
+restore-cursor@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+  integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
+  dependencies:
+    onetime "^5.1.0"
+    signal-exit "^3.0.2"
+
 ret@~0.1.10:
   version "0.1.15"
   resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@@ -9064,7 +10019,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
   dependencies:
     aproba "^1.1.1"
 
-rxjs@^6.4.0:
+rxjs@^6.1.0, rxjs@^6.4.0:
   version "6.5.2"
   resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7"
   integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==
@@ -9083,7 +10038,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
   integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
 
-safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2:
+safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
   version "5.2.0"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
   integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
@@ -9111,15 +10066,14 @@ sass-graph@^2.2.4:
     yargs "^7.0.0"
 
 sass-loader@^7.1.0:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d"
-  integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.2.0.tgz#e34115239309d15b2527cb62b5dfefb62a96ff7f"
+  integrity sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA==
   dependencies:
-    clone-deep "^2.0.1"
+    clone-deep "^4.0.1"
     loader-utils "^1.0.1"
-    lodash.tail "^4.1.1"
     neo-async "^2.5.0"
-    pify "^3.0.0"
+    pify "^4.0.1"
     semver "^5.5.0"
 
 sax@^1.2.4, sax@~1.2.4:
@@ -9159,6 +10113,11 @@ scss-tokenizer@^0.2.3:
     js-base64 "^2.1.8"
     source-map "^0.4.2"
 
+scuid@^1.0.2:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/scuid/-/scuid-1.1.0.tgz#d3f9f920956e737a60f72d0e4ad280bf324d5dab"
+  integrity sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==
+
 select-hose@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -9184,19 +10143,19 @@ semver-diff@^2.0.0:
     semver "^5.0.3"
 
 "semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
-  version "5.7.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
-  integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
 
 semver@5.5.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
   integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
 
-semver@^6.0.0, semver@^6.1.1, semver@^6.1.2:
-  version "6.2.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db"
-  integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==
+semver@^6.0.0, semver@^6.1.2, semver@^6.3.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
 
 semver@~5.0.1:
   version "5.0.3"
@@ -9227,11 +10186,26 @@ send@0.17.1:
     range-parser "~1.2.1"
     statuses "~1.5.0"
 
+sentence-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-2.1.1.tgz#1f6e2dda39c168bf92d13f86d4a918933f667ed4"
+  integrity sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case-first "^1.1.2"
+
 serialize-javascript@^1.4.0, serialize-javascript@^1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65"
   integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==
 
+serializerr@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/serializerr/-/serializerr-1.0.3.tgz#12d4c5aa1c3ffb8f6d1dc5f395aa9455569c3f91"
+  integrity sha1-EtTFqhw/+49tHcXzlaqUVVacP5E=
+  dependencies:
+    protochain "^1.0.5"
+
 serve-index@^1.9.1:
   version "1.9.1"
   resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
@@ -9293,14 +10267,12 @@ sha.js@^2.4.0, sha.js@^2.4.8:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
-shallow-clone@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571"
-  integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==
+shallow-clone@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
+  integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
   dependencies:
-    is-extendable "^0.1.1"
-    kind-of "^5.0.0"
-    mixin-object "^2.0.1"
+    kind-of "^6.0.2"
 
 shebang-command@^1.2.0:
   version "1.2.0"
@@ -9315,20 +10287,22 @@ shebang-regex@^1.0.0:
   integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
 
 shell-quote@^1.6.1:
-  version "1.6.1"
-  resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
-  integrity sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=
-  dependencies:
-    array-filter "~0.0.0"
-    array-map "~0.0.0"
-    array-reduce "~0.0.0"
-    jsonify "~0.0.0"
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.0.tgz#42d2e1d6d2438ae15b4812a626668f5708213394"
+  integrity sha512-+zdNWhJbPD3h5jR1LtZwVH+SpSBEzUhHUCHgAZFDKLGvIMR+PnJdsIx6ox7l1WYDT7s2mtjBiahyFAIT/+1ybw==
 
 signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
   integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
 
+simple-errors@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/simple-errors/-/simple-errors-1.0.1.tgz#b0bbecac1f1082f13b3962894b4a9e88f3a0c9ef"
+  integrity sha1-sLvsrB8QgvE7OWKJS0qeiPOgye8=
+  dependencies:
+    errno "^0.1.1"
+
 simple-swizzle@^0.2.2:
   version "0.2.2"
   resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
@@ -9360,6 +10334,13 @@ smart-buffer@^1.0.13:
   resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16"
   integrity sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=
 
+snake-case@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
+  integrity sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=
+  dependencies:
+    no-case "^2.2.0"
+
 snapdragon-node@^2.0.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -9450,10 +10431,10 @@ source-map-resolve@^0.5.0:
     source-map-url "^0.4.0"
     urix "^0.1.0"
 
-source-map-support@^0.5.0, source-map-support@~0.5.12:
-  version "0.5.12"
-  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
-  integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
+source-map-support@^0.5.0, source-map-support@^0.5.9, source-map-support@~0.5.12:
+  version "0.5.13"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
+  integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
   dependencies:
     buffer-from "^1.0.0"
     source-map "^0.6.0"
@@ -9518,10 +10499,10 @@ spdy-transport@^3.0.0:
     readable-stream "^3.0.6"
     wbuf "^1.7.3"
 
-spdy@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52"
-  integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==
+spdy@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.1.tgz#6f12ed1c5db7ea4f24ebb8b89ba58c87c08257f2"
+  integrity sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==
   dependencies:
     debug "^4.1.0"
     handle-thing "^2.0.0"
@@ -9668,6 +10649,15 @@ string-width@^3.0.0, string-width@^3.1.0:
     is-fullwidth-code-point "^2.0.0"
     strip-ansi "^5.1.0"
 
+string-width@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff"
+  integrity sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==
+  dependencies:
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^5.2.0"
+
 string.prototype.padend@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0"
@@ -9687,11 +10677,11 @@ string.prototype.padstart@^3.0.0:
     function-bind "^1.0.2"
 
 string_decoder@^1.0.0, string_decoder@^1.1.1:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
-  integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
   dependencies:
-    safe-buffer "~5.1.0"
+    safe-buffer "~5.2.0"
 
 string_decoder@~0.10.x:
   version "0.10.31"
@@ -9742,6 +10732,11 @@ strip-bom@^2.0.0:
   dependencies:
     is-utf8 "^0.2.0"
 
+strip-bom@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+  integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
+
 strip-comments@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-1.0.2.tgz#82b9c45e7f05873bee53f37168af930aa368679d"
@@ -9805,7 +10800,7 @@ supports-color@^2.0.0:
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
   integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
 
-supports-color@^5.3.0, supports-color@^5.4.0:
+supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
   integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
@@ -9843,6 +10838,14 @@ svgo@^1.0.0, svgo@^1.2.2:
     unquote "~1.1.1"
     util.promisify "~1.0.0"
 
+swap-case@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3"
+  integrity sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=
+  dependencies:
+    lower-case "^1.1.1"
+    upper-case "^1.1.1"
+
 symbol-observable@^1.0.2:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
@@ -9853,17 +10856,22 @@ symbol-tree@^3.2.2:
   resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
   integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
 
+sync-exec@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105"
+  integrity sha1-cX0izFPwzh3vVZQ2LzqJouu5EQU=
+
 table@^5.2.3:
-  version "5.4.4"
-  resolved "https://registry.yarnpkg.com/table/-/table-5.4.4.tgz#6e0f88fdae3692793d1077fd172a4667afe986a6"
-  integrity sha512-IIfEAUx5QlODLblLrGTTLJA7Tk0iLSGBvgY8essPRVNGHAzThujww1YqHLs6h3HfTg55h++RzLHH5Xw/rfv+mg==
+  version "5.4.5"
+  resolved "https://registry.yarnpkg.com/table/-/table-5.4.5.tgz#c8f4ea2d8fee08c0027fac27b0ec0a4fe01dfa42"
+  integrity sha512-oGa2Hl7CQjfoaogtrOHEJroOcYILTx7BZWLGsJIlzoWmB2zmguhNfPJZsWPKYek/MgCxfco54gEi31d1uN2hFA==
   dependencies:
     ajv "^6.10.2"
     lodash "^4.17.14"
     slice-ansi "^2.1.0"
     string-width "^3.0.0"
 
-tapable@^1.0.0, tapable@^1.1.0:
+tapable@^1.0.0, tapable@^1.1.0, tapable@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
   integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
@@ -9877,7 +10885,7 @@ tar@^2.0.0:
     fstream "^1.0.12"
     inherits "2"
 
-tar@^4:
+tar@^4, tar@^4.4.7:
   version "4.4.10"
   resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1"
   integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==
@@ -9905,26 +10913,25 @@ term-size@^1.2.0:
   dependencies:
     execa "^0.7.0"
 
-terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.2.3:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz#69aa22426299f4b5b3775cbed8cb2c5d419aa1d4"
-  integrity sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg==
+terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.2.3, terser-webpack-plugin@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4"
+  integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==
   dependencies:
-    cacache "^11.3.2"
-    find-cache-dir "^2.0.0"
+    cacache "^12.0.2"
+    find-cache-dir "^2.1.0"
     is-wsl "^1.1.0"
-    loader-utils "^1.2.3"
     schema-utils "^1.0.0"
     serialize-javascript "^1.7.0"
     source-map "^0.6.1"
-    terser "^4.0.0"
-    webpack-sources "^1.3.0"
+    terser "^4.1.2"
+    webpack-sources "^1.4.0"
     worker-farm "^1.7.0"
 
-terser@^4.0.0:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.2.tgz#b2656c8a506f7ce805a3f300a2ff48db022fa391"
-  integrity sha512-jvNoEQSPXJdssFwqPSgWjsOrb+ELoE+ILpHPKXC83tIxOlh2U75F1KuB2luLD/3a6/7K3Vw5pDn+hvu0C4AzSw==
+terser@^4.1.2:
+  version "4.1.4"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.4.tgz#4478b6a08bb096a61e793fea1a4434408bab936c"
+  integrity sha512-+ZwXJvdSwbd60jG0Illav0F06GDJF0R4ydZ21Q3wGAFKoBGyJGo34F63vzJHgvYxc1ukOtIjvwEvl9MkjzM6Pg==
   dependencies:
     commander "^2.20.0"
     source-map "~0.6.1"
@@ -9950,9 +10957,9 @@ thenify-all@^1.0.0:
     any-promise "^1.0.0"
 
 thread-loader@^2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/thread-loader/-/thread-loader-2.1.2.tgz#f585dd38e852c7f9cded5d092992108148f5eb30"
-  integrity sha512-7xpuc9Ifg6WU+QYw/8uUqNdRwMD+N5gjwHKMqETrs96Qn+7BHwECpt2Brzr4HFlf4IAkZsayNhmGdbkBsTJ//w==
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/thread-loader/-/thread-loader-2.1.3.tgz#cbd2c139fc2b2de6e9d28f62286ab770c1acbdda"
+  integrity sha512-wNrVKH2Lcf8ZrWxDF/khdlLlsTMczdcwPA9VEK4c2exlEPynYWxi9op3nPTo5lAnDIkE0rQEB3VBP+4Zncc9Hg==
   dependencies:
     loader-runner "^2.3.1"
     loader-utils "^1.1.0"
@@ -9963,7 +10970,7 @@ throttle-debounce@^2.1.0:
   resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.1.0.tgz#257e648f0a56bd9e54fe0f132c4ab8611df4e1d5"
   integrity sha512-AOvyNahXQuU7NN+VVvOOX+uW6FPaWdAOdRP5HfwYxAfCzXTFKRMoIMk+n+po318+ktcChx+F1Dd91G3YHeMKyg==
 
-through2@^2.0.0:
+through2@^2.0.0, through2@^2.0.3:
   version "2.0.5"
   resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
   integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
@@ -9992,9 +10999,9 @@ timed-out@^4.0.0:
   integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
 
 timers-browserify@^2.0.4:
-  version "2.0.10"
-  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae"
-  integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==
+  version "2.0.11"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f"
+  integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==
   dependencies:
     setimmediate "^1.0.4"
 
@@ -10004,57 +11011,57 @@ timsort@^0.3.0:
   integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
 
 tippy.js@^4.3.1:
-  version "4.3.4"
-  resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-4.3.4.tgz#9a91fd5ce8c401f181b7adaa6b2c27f3d105f3ba"
-  integrity sha512-O2ukxHOJTLVYZ/TfHjNd8WgAWoefX9uk5QiWRdHfX2PR2lBpUU4BJQLl7U2Ykc8K7o16gTeHEElpuRfgD5b0aA==
+  version "4.3.5"
+  resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-4.3.5.tgz#882bff8d92f09bb0546d2826d5668c0560006f54"
+  integrity sha512-NDq3efte8nGK6BOJ1dDN1/WelAwfmh3UtIYXXck6+SxLzbIQNZE/cmRSnwScZ/FyiKdIcvFHvYUgqmoGx8CcyA==
   dependencies:
     popper.js "^1.14.7"
 
-tiptap-commands@^1.10.10:
-  version "1.10.10"
-  resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.10.10.tgz#41c882ee7385c00a5613cbb2d6192181d791da10"
-  integrity sha512-5MYWuKQQaJzXbhL1uYG8ndQy5zlGMwt4Mct/VRInfydq1QWZsn2fg8+J87fu1wSY4LbRqn1oki0j67L4YznXMQ==
+tiptap-commands@^1.10.12:
+  version "1.10.12"
+  resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.10.12.tgz#9d3f001b371319c6b1a131623ca8e74a46363b9d"
+  integrity sha512-cNIYIbP2gvdP08mFivezNmyJscBLthjPtVzlbXNu4963an7guOSpKYl4aImJLVbKlAIk5W1P/TlhjyPQodDIgw==
   dependencies:
     prosemirror-commands "^1.0.8"
     prosemirror-inputrules "^1.0.4"
     prosemirror-model "^1.7.1"
     prosemirror-schema-list "^1.0.3"
     prosemirror-state "^1.2.3"
-    prosemirror-tables "^0.8.1"
-    prosemirror-utils "^0.9.4"
-    tiptap-utils "^1.5.8"
+    prosemirror-tables "^0.9.1"
+    prosemirror-utils "^0.9.6"
+    tiptap-utils "^1.6.1"
 
 tiptap-extensions@^1.20.1:
-  version "1.24.4"
-  resolved "https://registry.yarnpkg.com/tiptap-extensions/-/tiptap-extensions-1.24.4.tgz#533c8fe91c8271b840716a0e237a76ced63a6914"
-  integrity sha512-sut1Z3TU2R7HqPh/n3dIbR72lN2HL901+Ql+PCiQHtKH1EK0WuHBTTOJrDIvap57lI5fI1Sx/iScGoGyB1MkqQ==
+  version "1.26.1"
+  resolved "https://registry.yarnpkg.com/tiptap-extensions/-/tiptap-extensions-1.26.1.tgz#f0fa492f268f73e4a4313de5de8d22799988ae39"
+  integrity sha512-Qzr63TOhZLLKw4A/F/EnxwWtdDELA0w6ogk/cKI+xmDUM14RN6VsVoz3QVZyuyzC/ceiQ6dV/iP67PJJ6kvKTw==
   dependencies:
     lowlight "^1.12.1"
     prosemirror-collab "^1.1.2"
     prosemirror-history "^1.0.4"
     prosemirror-model "^1.7.1"
     prosemirror-state "^1.2.3"
-    prosemirror-tables "^0.8.1"
+    prosemirror-tables "^0.9.1"
     prosemirror-transform "^1.1.3"
-    prosemirror-utils "^0.9.4"
-    prosemirror-view "^1.9.12"
-    tiptap "^1.23.4"
-    tiptap-commands "^1.10.10"
+    prosemirror-utils "^0.9.6"
+    prosemirror-view "^1.9.13"
+    tiptap "^1.24.1"
+    tiptap-commands "^1.10.12"
 
-tiptap-utils@^1.5.8:
-  version "1.5.8"
-  resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.5.8.tgz#b7e6937d9d85f0a8473725b9a60e064bdda781c7"
-  integrity sha512-FkKmTzEHFr9wEDqu4rwegooFW2xjUzhbBP7sWXM1T57ZxLDcUBW60n2KiMLTswKcyMRryoRx0ZtwRmeole+1RQ==
+tiptap-utils@^1.6.1:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.6.1.tgz#4bd1aa160728286274512d0b3773f5b5d39b70cb"
+  integrity sha512-N7UPvOjTW8bCdY9EsZki7MBdFKIFoZ8V1whjxuwBu6VSvLKpIKGaHsGDAnYgvrAhPVYVIdZU7OreU/805JmwWg==
   dependencies:
     prosemirror-model "^1.7.1"
     prosemirror-state "^1.2.3"
-    prosemirror-tables "^0.8.1"
-    prosemirror-utils "^0.9.4"
+    prosemirror-tables "^0.9.1"
+    prosemirror-utils "^0.9.6"
 
-tiptap@^1.20.1, tiptap@^1.23.4:
-  version "1.23.4"
-  resolved "https://registry.yarnpkg.com/tiptap/-/tiptap-1.23.4.tgz#c96460577c241a4ffc5df2158950013165c1ac81"
-  integrity sha512-TQ5SYXELryxlkTUc5lTRhcEDr0HikCRzLqaI+umpa6d2fOrJ3bVbS1GrQxe4ctDWDdGA/UQHfmfzFcECKO6TKg==
+tiptap@^1.20.1, tiptap@^1.24.1:
+  version "1.24.1"
+  resolved "https://registry.yarnpkg.com/tiptap/-/tiptap-1.24.1.tgz#ecbc4c42be37c26dd73bf3969af1fe20befad8b7"
+  integrity sha512-/4ABBDoEoDbFCHQQ65clEAjTxqR3DX1PQDsjp7LnYjPiVMGLL11NKnyT1kAn8QNaNGzV+uSSgkROBArcsiF5eA==
   dependencies:
     prosemirror-commands "^1.0.8"
     prosemirror-dropcursor "^1.1.1"
@@ -10063,9 +11070,25 @@ tiptap@^1.20.1, tiptap@^1.23.4:
     prosemirror-keymap "^1.0.1"
     prosemirror-model "^1.7.1"
     prosemirror-state "^1.2.3"
-    prosemirror-view "^1.9.12"
-    tiptap-commands "^1.10.10"
-    tiptap-utils "^1.5.8"
+    prosemirror-view "^1.9.13"
+    tiptap-commands "^1.10.12"
+    tiptap-utils "^1.6.1"
+
+title-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"
+  integrity sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.0.3"
+
+tmp-graphql-config-extension-openapi@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/tmp-graphql-config-extension-openapi/-/tmp-graphql-config-extension-openapi-1.0.7.tgz#e651552bf6c57e473b088434940aba2b757c2b4c"
+  integrity sha512-NQPUaywaVC2hzWkBBsTX3sV2XfxU0mc409rJyrA7iCu5DSTjMLUqI+U4KJVSy/Ltp0zgbWMWua471R7zMql9Pw==
+  dependencies:
+    "@kbrandwijk/swagger-to-graphql" "2.4.3"
+    graphql-config "2.2.1"
 
 tmp@^0.0.33:
   version "0.0.33"
@@ -10074,6 +11097,13 @@ tmp@^0.0.33:
   dependencies:
     os-tmpdir "~1.0.2"
 
+tmp@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877"
+  integrity sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==
+  dependencies:
+    rimraf "^2.6.3"
+
 to-arraybuffer@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
@@ -10159,6 +11189,11 @@ tr46@^1.0.1:
   dependencies:
     punycode "^2.1.0"
 
+traverse-chain@~0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
+  integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=
+
 trim-newlines@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
@@ -10284,9 +11319,9 @@ tsutils@^2.29.0:
     tslib "^1.8.1"
 
 tsutils@^3.0.0, tsutils@^3.5.0, tsutils@^3.7.0:
-  version "3.14.0"
-  resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.14.0.tgz#bf8d5a7bae5369331fa0f2b0a5a10bd7f7396c77"
-  integrity sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==
+  version "3.17.1"
+  resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
+  integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
   dependencies:
     tslib "^1.8.1"
 
@@ -10324,12 +11359,17 @@ type-detect@^4.0.0, type-detect@^4.0.5:
   resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
   integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
 
+type-fest@^0.5.2:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2"
+  integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==
+
 type-fest@^0.6.0:
   version "0.6.0"
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
   integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
 
-type-is@~1.6.17, type-is@~1.6.18:
+type-is@^1.6.16, type-is@~1.6.17, type-is@~1.6.18:
   version "1.6.18"
   resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
   integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
@@ -10488,7 +11528,14 @@ update-notifier@^2.5.0:
     semver-diff "^2.0.0"
     xdg-basedir "^3.0.0"
 
-upper-case@^1.1.1:
+upper-case-first@^1.1.0, upper-case-first@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115"
+  integrity sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=
+  dependencies:
+    upper-case "^1.1.1"
+
+upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
   integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
@@ -10505,6 +11552,11 @@ urix@^0.1.0:
   resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
   integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
 
+url-join@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a"
+  integrity sha1-TTNA6AfTdzvamZH4MFrNzCpmXSo=
+
 url-loader@^1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.1.2.tgz#b971d191b83af693c5e3fea4064be9e1f2d7f8d8"
@@ -10529,6 +11581,13 @@ url-parse@^1.4.3:
     querystringify "^2.1.1"
     requires-port "^1.0.0"
 
+url-regex@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/url-regex/-/url-regex-3.2.0.tgz#dbad1e0c9e29e105dd0b1f09f6862f7fdb482724"
+  integrity sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=
+  dependencies:
+    ip-regex "^1.0.1"
+
 url@^0.11.0:
   version "0.11.0"
   resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
@@ -10585,9 +11644,9 @@ uuid@^3.0.1, uuid@^3.3.2:
   integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
 
 v8-compile-cache@^2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
-  integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
+  integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
 
 validate-npm-package-license@^3.0.1:
   version "3.0.4"
@@ -10597,6 +11656,11 @@ validate-npm-package-license@^3.0.1:
     spdx-correct "^3.0.0"
     spdx-expression-parse "^3.0.0"
 
+validator@^10.0.0:
+  version "10.11.0"
+  resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
+  integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
+
 vary@~1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
@@ -10677,9 +11741,9 @@ vue-property-decorator@^8.1.0:
     vue-class-component "^7.0.1"
 
 vue-router@^3.0.6:
-  version "3.0.7"
-  resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.7.tgz#b36ca107b4acb8ff5bc4ff824584059c23fcb87b"
-  integrity sha512-utJ+QR3YlIC/6x6xq17UMXeAfxEvXA0VKD3PiSio7hBOZNusA1jXcbxZxVEfJunLp48oonjTepY8ORoIlRx/EQ==
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.1.2.tgz#2e0904703545dabdd42b2b7a2e617f02f99a1969"
+  integrity sha512-WssQEHSEvIS1/CI4CO2T8LJdoK4Q9Ngox28K7FDNMTfzNTk2WS5D0dDlqYCaPG+AG4Z8wJkn1KrBc7AhspZJUQ==
 
 vue-style-loader@^4.1.0:
   version "4.1.2"
@@ -10715,9 +11779,9 @@ vue-template-es2015-compiler@^1.6.0, vue-template-es2015-compiler@^1.9.0:
   integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
 
 vue2-leaflet@^2.0.3:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/vue2-leaflet/-/vue2-leaflet-2.1.1.tgz#33ec8920bd1e273b312209a84ce355021226ee79"
-  integrity sha512-boJIObTHJOtiLqPDtcL8FdQMr/PLDyZ6/InQBU13mcmNtn4/hvzbyqLmVtvWbRFeGOifAMkJBlbj3gLjrhFdmw==
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/vue2-leaflet/-/vue2-leaflet-2.2.1.tgz#cd67274951751a33df147481fce2b956ba174c7e"
+  integrity sha512-yBB3Ilv9LTszNn/uxUATq8+Ahw/1FqIasdQehb9m1tJ5T9qeEk8Fr9a6uLzvR+zuz88rnEQVo7/iGUd96E7iLg==
 
 vue@^2.6.10:
   version "2.6.10"
@@ -10750,7 +11814,7 @@ w3c-xmlserializer@^1.0.1:
     webidl-conversions "^4.0.2"
     xml-name-validator "^3.0.0"
 
-watchpack@^1.5.0:
+watchpack@^1.5.0, watchpack@^1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
   integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==
@@ -10766,7 +11830,7 @@ wbuf@^1.1.0, wbuf@^1.7.3:
   dependencies:
     minimalistic-assert "^1.0.0"
 
-wcwidth@^1.0.1:
+wcwidth@^1.0.0, wcwidth@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
   integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
@@ -10779,9 +11843,9 @@ webidl-conversions@^4.0.2:
   integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
 
 webpack-bundle-analyzer@^3.3.0, webpack-bundle-analyzer@^3.3.2:
-  version "3.3.2"
-  resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.3.2.tgz#3da733a900f515914e729fcebcd4c40dde71fc6f"
-  integrity sha512-7qvJLPKB4rRWZGjVp5U1KEjwutbDHSKboAl0IfafnrdXMrgC0tOtZbQD6Rw0u4cmpgRN4O02Fc0t8eAT+FgGzA==
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.4.1.tgz#430544c7ba1631baccf673475ca8300cb74a3c47"
+  integrity sha512-Bs8D/1zF+17lhqj2OYmzi7HEVYqEVxu7lCO9Ff8BwajenOU0vAwEoV8e4ICCPNZAcqR1PCR/7o2SkW+cnCmF0A==
   dependencies:
     acorn "^6.0.7"
     acorn-walk "^6.1.1"
@@ -10792,7 +11856,7 @@ webpack-bundle-analyzer@^3.3.0, webpack-bundle-analyzer@^3.3.2:
     express "^4.16.3"
     filesize "^3.6.1"
     gzip-size "^5.0.0"
-    lodash "^4.17.10"
+    lodash "^4.17.15"
     mkdirp "^0.5.1"
     opener "^1.5.1"
     ws "^6.0.0"
@@ -10816,9 +11880,9 @@ webpack-dev-middleware@^3.7.0:
     webpack-log "^2.0.0"
 
 webpack-dev-server@^3.4.1:
-  version "3.7.2"
-  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.7.2.tgz#f79caa5974b7f8b63268ef5421222a8486d792f5"
-  integrity sha512-mjWtrKJW2T9SsjJ4/dxDC2fkFVUw8jlpemDERqV0ZJIkjjjamR2AbQlr3oz+j4JLhYCHImHnXZK5H06P2wvUew==
+  version "3.8.0"
+  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.8.0.tgz#06cc4fc2f440428508d0e9770da1fef10e5ef28d"
+  integrity sha512-Hs8K9yI6pyMvGkaPTeTonhD6JXVsigXDApYk9JLW4M7viVBspQvb1WdAcWxqtmttxNW4zf2UFLsLNe0y87pIGQ==
   dependencies:
     ansi-html "0.0.7"
     bonjour "^3.5.0"
@@ -10833,23 +11897,25 @@ webpack-dev-server@^3.4.1:
     import-local "^2.0.0"
     internal-ip "^4.3.0"
     ip "^1.1.5"
+    is-absolute-url "^3.0.0"
     killable "^1.0.1"
     loglevel "^1.6.3"
     opn "^5.5.0"
     p-retry "^3.0.1"
-    portfinder "^1.0.20"
+    portfinder "^1.0.21"
     schema-utils "^1.0.0"
     selfsigned "^1.10.4"
-    semver "^6.1.1"
+    semver "^6.3.0"
     serve-index "^1.9.1"
     sockjs "0.3.19"
     sockjs-client "1.3.0"
-    spdy "^4.0.0"
+    spdy "^4.0.1"
     strip-ansi "^3.0.1"
     supports-color "^6.1.0"
     url "^0.11.0"
     webpack-dev-middleware "^3.7.0"
     webpack-log "^2.0.0"
+    ws "^6.2.1"
     yargs "12.0.5"
 
 webpack-log@^2.0.0:
@@ -10867,10 +11933,10 @@ webpack-merge@^4.2.1:
   dependencies:
     lodash "^4.17.5"
 
-webpack-sources@^1.1.0, webpack-sources@^1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
-  integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==
+webpack-sources@^1.1.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1:
+  version "1.4.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
+  integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
   dependencies:
     source-list-map "^2.0.0"
     source-map "~0.6.1"
@@ -10906,33 +11972,33 @@ webpack-sources@^1.1.0, webpack-sources@^1.3.0:
     webpack-sources "^1.3.0"
 
 webpack@^4.30.0:
-  version "4.37.0"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.37.0.tgz#3508ef10f7996612c2be6026076d89760f776f54"
-  integrity sha512-iJPPvL7XpbcbwOthbzpa2BSPlmGp8lGDokAj/LdWtK80rsPoPOdANSbDBf2GAVLKZD3GhCuQ/gGkgN9HWs0Keg==
+  version "4.39.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.39.1.tgz#60ed9fb2b72cd60f26ea526c404d2a4cc97a1bd8"
+  integrity sha512-/LAb2TJ2z+eVwisldp3dqTEoNhzp/TLCZlmZm3GGGAlnfIWDgOEE758j/9atklNLfRyhKbZTCOIoPqLJXeBLbQ==
   dependencies:
     "@webassemblyjs/ast" "1.8.5"
     "@webassemblyjs/helper-module-context" "1.8.5"
     "@webassemblyjs/wasm-edit" "1.8.5"
     "@webassemblyjs/wasm-parser" "1.8.5"
-    acorn "^6.2.0"
-    ajv "^6.1.0"
-    ajv-keywords "^3.1.0"
-    chrome-trace-event "^1.0.0"
+    acorn "^6.2.1"
+    ajv "^6.10.2"
+    ajv-keywords "^3.4.1"
+    chrome-trace-event "^1.0.2"
     enhanced-resolve "^4.1.0"
-    eslint-scope "^4.0.0"
+    eslint-scope "^4.0.3"
     json-parse-better-errors "^1.0.2"
-    loader-runner "^2.3.0"
-    loader-utils "^1.1.0"
-    memory-fs "~0.4.1"
-    micromatch "^3.1.8"
-    mkdirp "~0.5.0"
-    neo-async "^2.5.0"
-    node-libs-browser "^2.0.0"
+    loader-runner "^2.4.0"
+    loader-utils "^1.2.3"
+    memory-fs "^0.4.1"
+    micromatch "^3.1.10"
+    mkdirp "^0.5.1"
+    neo-async "^2.6.1"
+    node-libs-browser "^2.2.1"
     schema-utils "^1.0.0"
-    tapable "^1.1.0"
-    terser-webpack-plugin "^1.1.0"
-    watchpack "^1.5.0"
-    webpack-sources "^1.3.0"
+    tapable "^1.1.3"
+    terser-webpack-plugin "^1.4.1"
+    watchpack "^1.6.0"
+    webpack-sources "^1.4.1"
 
 websocket-driver@>=0.5.1:
   version "0.7.3"
@@ -10955,6 +12021,16 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5:
   dependencies:
     iconv-lite "0.4.24"
 
+whatwg-fetch@2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
+  integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==
+
+whatwg-fetch@>=0.10.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
+  integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==
+
 whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
@@ -10979,7 +12055,7 @@ which-module@^2.0.0:
   resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
   integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
 
-which@1, which@^1.2.9:
+which@1, which@^1.2.10, which@^1.2.14, which@^1.2.9:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
   integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -11200,7 +12276,7 @@ write@1.0.3:
   dependencies:
     mkdirp "^0.5.1"
 
-ws@^6.0.0, ws@^6.1.2:
+ws@^6.0.0, ws@^6.1.2, ws@^6.2.1:
   version "6.2.1"
   resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
   integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
@@ -11252,6 +12328,11 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
   integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
 
+yaml-ast-parser@^0.0.40:
+  version "0.0.40"
+  resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.40.tgz#08536d4e73d322b1c9ce207ab8dd70e04d20ae6e"
+  integrity sha1-CFNtTnPTIrHJziB6uN1w4E0grm4=
+
 yargs-parser@^11.1.1:
   version "11.1.1"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
@@ -11275,6 +12356,20 @@ yargs-parser@^5.0.0:
   dependencies:
     camelcase "^3.0.0"
 
+yargs-parser@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9"
+  integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k=
+  dependencies:
+    camelcase "^4.1.0"
+
+yargs-parser@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950"
+  integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==
+  dependencies:
+    camelcase "^4.1.0"
+
 yargs-parser@^9.0.2:
   version "9.0.2"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077"
@@ -11300,6 +12395,24 @@ yargs@12.0.5:
     y18n "^3.2.1 || ^4.0.0"
     yargs-parser "^11.1.1"
 
+yargs@^10.0.3:
+  version "10.1.2"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5"
+  integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==
+  dependencies:
+    cliui "^4.0.0"
+    decamelize "^1.1.1"
+    find-up "^2.1.0"
+    get-caller-file "^1.0.1"
+    os-locale "^2.0.0"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^2.0.0"
+    which-module "^2.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^8.1.0"
+
 yargs@^11.0.0:
   version "11.1.0"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77"
@@ -11353,6 +12466,25 @@ yargs@^7.0.0:
     y18n "^3.2.1"
     yargs-parser "^5.0.0"
 
+yargs@^8.0.2:
+  version "8.0.2"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360"
+  integrity sha1-YpmpBVsc78lp/355wdkY3Osiw2A=
+  dependencies:
+    camelcase "^4.1.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^2.0.0"
+    read-pkg-up "^2.0.0"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^2.0.0"
+    which-module "^2.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^7.0.0"
+
 yargs@~3.10.0:
   version "3.10.0"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
@@ -11380,6 +12512,18 @@ yorkie@^2.0.0:
     normalize-path "^1.0.0"
     strip-indent "^2.0.0"
 
+z-schema@^3.18.2:
+  version "3.25.1"
+  resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-3.25.1.tgz#7e14663be2b96003d938a56f644fb8561643fb7e"
+  integrity sha512-7tDlwhrBG+oYFdXNOjILSurpfQyuVgkRe3hB2q8TEssamDHB7BbLWYkYO98nTn0FibfdFroFKDjndbgufAgS/Q==
+  dependencies:
+    core-js "^2.5.7"
+    lodash.get "^4.0.0"
+    lodash.isequal "^4.0.0"
+    validator "^10.0.0"
+  optionalDependencies:
+    commander "^2.7.1"
+
 zen-observable-ts@^0.8.19:
   version "0.8.19"
   resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.19.tgz#c094cd20e83ddb02a11144a6e2a89706946b5694"
diff --git a/lib/mix/tasks/mobilizon/common.ex b/lib/mix/tasks/mobilizon/common.ex
index cb18bcbd2..a511ddc7e 100644
--- a/lib/mix/tasks/mobilizon/common.ex
+++ b/lib/mix/tasks/mobilizon/common.ex
@@ -22,6 +22,11 @@ defmodule Mix.Tasks.Mobilizon.Common do
       end
   end
 
+  def start_mobilizon do
+    Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
+    {:ok, _} = Application.ensure_all_started(:mobilizon)
+  end
+
   def escape_sh_path(path) do
     ~S(') <> String.replace(path, ~S('), ~S(\')) <> ~S(')
   end
diff --git a/lib/mix/tasks/mobilizon/relay.ex b/lib/mix/tasks/mobilizon/relay.ex
new file mode 100644
index 000000000..e4db70f12
--- /dev/null
+++ b/lib/mix/tasks/mobilizon/relay.ex
@@ -0,0 +1,65 @@
+# Portions of this file are derived from Pleroma:
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social>
+# SPDX-License-Identifier: AGPL-3.0-only
+# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/mix/tasks/pleroma/relay.ex
+
+defmodule Mix.Tasks.Mobilizon.Relay do
+  use Mix.Task
+  alias Mobilizon.Service.ActivityPub.Relay
+  alias Mix.Tasks.Mobilizon.Common
+
+  @shortdoc "Manages remote relays"
+  @moduledoc """
+  Manages remote relays
+
+  ## Follow a remote relay
+
+  ``mix mobilizon.relay follow <relay_url>``
+
+  Example: ``mix mobilizon.relay follow  https://example.org/relay``
+
+  ## Unfollow a remote relay
+
+  ``mix mobilizon.relay unfollow <relay_url>``
+
+  Example: ``mix mobilizon.relay unfollow https://example.org/relay``
+  """
+  def run(["follow", target]) do
+    Common.start_mobilizon()
+
+    case Relay.follow(target) do
+      {:ok, _activity} ->
+        # put this task to sleep to allow the genserver to push out the messages
+        :timer.sleep(500)
+
+      {:error, e} ->
+        IO.puts(:stderr, "Error while following #{target}: #{inspect(e)}")
+    end
+  end
+
+  def run(["unfollow", target]) do
+    Common.start_mobilizon()
+
+    case Relay.unfollow(target) do
+      {:ok, _activity} ->
+        # put this task to sleep to allow the genserver to push out the messages
+        :timer.sleep(500)
+
+      {:error, e} ->
+        IO.puts(:stderr, "Error while unfollowing #{target}: #{inspect(e)}")
+    end
+  end
+
+  def run(["accept", target]) do
+    Common.start_mobilizon()
+
+    case Relay.accept(target) do
+      {:ok, _activity} ->
+        # put this task to sleep to allow the genserver to push out the messages
+        :timer.sleep(500)
+
+      {:error, e} ->
+        IO.puts(:stderr, "Error while accept #{target} follow: #{inspect(e)}")
+    end
+  end
+end
diff --git a/lib/mobilizon/actors/actor.ex b/lib/mobilizon/actors/actor.ex
index 926bbc448..ba4477e8f 100644
--- a/lib/mobilizon/actors/actor.ex
+++ b/lib/mobilizon/actors/actor.ex
@@ -163,7 +163,6 @@ defmodule Mobilizon.Actors.Actor do
       ])
       |> validate_required([
         :url,
-        :outbox_url,
         :inbox_url,
         :type,
         :domain,
@@ -184,6 +183,44 @@ defmodule Mobilizon.Actors.Actor do
     changes
   end
 
+  def relay_creation(%{url: url, preferred_username: preferred_username} = _params) do
+    key = :public_key.generate_key({:rsa, 2048, 65_537})
+    entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
+    pem = [entry] |> :public_key.pem_encode() |> String.trim_trailing()
+
+    vars = %{
+      "name" => Mobilizon.CommonConfig.get([:instance, :name], "Mobilizon"),
+      "summary" =>
+        Mobilizon.CommonConfig.get(
+          [:instance, :description],
+          "An internal service actor for this Mobilizon instance"
+        ),
+      "url" => url,
+      "keys" => pem,
+      "preferred_username" => preferred_username,
+      "domain" => nil,
+      "inbox_url" => "#{MobilizonWeb.Endpoint.url()}/inbox",
+      "followers_url" => "#{url}/followers",
+      "following_url" => "#{url}/following",
+      "shared_inbox_url" => "#{MobilizonWeb.Endpoint.url()}/inbox",
+      "type" => :Application
+    }
+
+    cast(%Actor{}, vars, [
+      :type,
+      :name,
+      :summary,
+      :url,
+      :keys,
+      :preferred_username,
+      :domain,
+      :inbox_url,
+      :followers_url,
+      :following_url,
+      :shared_inbox_url
+    ])
+  end
+
   @doc """
   Changeset for group creation
   """
@@ -240,6 +277,14 @@ defmodule Mobilizon.Actors.Actor do
       :outbox_url,
       build_url(username, :outbox)
     )
+    |> put_change(
+      :followers_url,
+      build_url(username, :followers)
+    )
+    |> put_change(
+      :following_url,
+      build_url(username, :following)
+    )
     |> put_change(
       :inbox_url,
       build_url(username, :inbox)
@@ -325,18 +370,30 @@ defmodule Mobilizon.Actors.Actor do
     %{total: Task.await(total), elements: Task.await(elements)}
   end
 
-  @spec get_full_followers(struct()) :: list()
-  def get_full_followers(%Actor{id: actor_id} = _actor) do
-    Repo.all(
-      from(
-        a in Actor,
-        join: f in Follower,
-        on: a.id == f.actor_id,
-        where: f.target_actor_id == ^actor_id
-      )
+  defp get_full_followers_query(%Actor{id: actor_id} = _actor) do
+    from(
+      a in Actor,
+      join: f in Follower,
+      on: a.id == f.actor_id,
+      where: f.target_actor_id == ^actor_id
     )
   end
 
+  @spec get_full_followers(struct()) :: list()
+  def get_full_followers(%Actor{} = actor) do
+    actor
+    |> get_full_followers_query()
+    |> Repo.all()
+  end
+
+  @spec get_full_external_followers(struct()) :: list()
+  def get_full_external_followers(%Actor{} = actor) do
+    actor
+    |> get_full_followers_query()
+    |> where([a], not is_nil(a.domain))
+    |> Repo.all()
+  end
+
   @doc """
   Get followings from an actor
 
@@ -404,18 +461,19 @@ defmodule Mobilizon.Actors.Actor do
   Make an actor follow another
   """
   @spec follow(struct(), struct(), boolean()) :: Follower.t() | {:error, String.t()}
-  def follow(%Actor{} = followed, %Actor{} = follower, approved \\ true) do
+  def follow(%Actor{} = followed, %Actor{} = follower, url \\ nil, approved \\ true) do
     with {:suspended, false} <- {:suspended, followed.suspended},
          # Check if followed has blocked follower
          {:already_following, false} <- {:already_following, following?(follower, followed)} do
-      do_follow(follower, followed, approved)
+      do_follow(follower, followed, approved, url)
     else
       {:already_following, %Follower{}} ->
-        {:error,
+        {:error, :already_following,
          "Could not follow actor: you are already following #{followed.preferred_username}"}
 
       {:suspended, _} ->
-        {:error, "Could not follow actor: #{followed.preferred_username} has been suspended"}
+        {:error, :suspended,
+         "Could not follow actor: #{followed.preferred_username} has been suspended"}
     end
   end
 
@@ -433,13 +491,20 @@ defmodule Mobilizon.Actors.Actor do
     end
   end
 
-  @spec do_follow(struct(), struct(), boolean) ::
+  @spec do_follow(struct(), struct(), boolean(), String.t()) ::
           {:ok, Follower.t()} | {:error, Ecto.Changeset.t()}
-  defp do_follow(%Actor{} = follower, %Actor{} = followed, approved) do
+  defp do_follow(%Actor{} = follower, %Actor{} = followed, approved, url) do
+    Logger.info(
+      "Making #{follower.preferred_username} follow #{followed.preferred_username} (approved: #{
+        approved
+      })"
+    )
+
     Actors.create_follower(%{
       "actor_id" => follower.id,
       "target_actor_id" => followed.id,
-      "approved" => approved
+      "approved" => approved,
+      "url" => url
     })
   end
 
diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex
index 129bd34cb..5792d9cad 100644
--- a/lib/mobilizon/actors/actors.ex
+++ b/lib/mobilizon/actors/actors.ex
@@ -297,7 +297,7 @@ defmodule Mobilizon.Actors do
         {:ok, actor}
 
       err ->
-        Logger.error(inspect(err))
+        Logger.debug(inspect(err))
         {:error, err}
     end
   end
@@ -475,16 +475,16 @@ defmodule Mobilizon.Actors do
   @spec get_or_fetch_by_url(String.t(), bool()) :: {:ok, Actor.t()} | {:error, String.t()}
   def get_or_fetch_by_url(url, preload \\ false) do
     case get_actor_by_url(url, preload) do
-      {:ok, actor} ->
+      {:ok, %Actor{} = actor} ->
         {:ok, actor}
 
       _ ->
         case ActivityPub.make_actor_from_url(url, preload) do
-          {:ok, actor} ->
+          {:ok, %Actor{} = actor} ->
             {:ok, actor}
 
           _ ->
-            Logger.error("Could not fetch by AP id")
+            Logger.warn("Could not fetch by AP id")
             {:error, "Could not fetch by AP id"}
         end
     end
@@ -655,6 +655,18 @@ defmodule Mobilizon.Actors do
     end
   end
 
+  def get_or_create_service_actor_by_url(url, preferred_username \\ "relay") do
+    case get_actor_by_url(url) do
+      {:ok, %Actor{} = actor} ->
+        {:ok, actor}
+
+      _ ->
+        %{url: url, preferred_username: preferred_username}
+        |> Actor.relay_creation()
+        |> Repo.insert()
+    end
+  end
+
   alias Mobilizon.Actors.Member
 
   @doc """
@@ -895,7 +907,7 @@ defmodule Mobilizon.Actors do
   end
 
   @doc """
-  Get a follower by the followed actor and following actor
+  Get a follow by the followed actor and following actor
   """
   @spec get_follower(Actor.t(), Actor.t()) :: Follower.t()
   def get_follower(%Actor{id: followed_id}, %Actor{id: follower_id}) do
@@ -904,6 +916,19 @@ defmodule Mobilizon.Actors do
     )
   end
 
+  @doc """
+  Get a follow by the followed actor and following actor
+  """
+  @spec get_follow_by_url(String.t()) :: Follower.t()
+  def get_follow_by_url(url) do
+    Repo.one(
+      from(f in Follower,
+        where: f.url == ^url,
+        preload: [:actor, :target_actor]
+      )
+    )
+  end
+
   @doc """
   Creates a follower.
 
@@ -1009,7 +1034,7 @@ defmodule Mobilizon.Actors do
 
       {:error, error} ->
         Logger.error("Error while removing an upload file")
-        Logger.error(inspect(error))
+        Logger.debug(inspect(error))
         {:ok, actor}
     end
   end
diff --git a/lib/mobilizon/actors/follower.ex b/lib/mobilizon/actors/follower.ex
index a25fec3a5..426706737 100644
--- a/lib/mobilizon/actors/follower.ex
+++ b/lib/mobilizon/actors/follower.ex
@@ -7,9 +7,11 @@ defmodule Mobilizon.Actors.Follower do
   alias Mobilizon.Actors.Follower
   alias Mobilizon.Actors.Actor
 
+  @primary_key {:id, :binary_id, autogenerate: true}
+
   schema "followers" do
     field(:approved, :boolean, default: false)
-    field(:score, :integer, default: 1000)
+    field(:url, :string)
     belongs_to(:target_actor, Actor)
     belongs_to(:actor, Actor)
   end
@@ -17,8 +19,34 @@ defmodule Mobilizon.Actors.Follower do
   @doc false
   def changeset(%Follower{} = member, attrs) do
     member
-    |> cast(attrs, [:score, :approved, :target_actor_id, :actor_id])
-    |> validate_required([:score, :approved, :target_actor_id, :actor_id])
+    |> cast(attrs, [:url, :approved, :target_actor_id, :actor_id])
+    |> generate_url()
+    |> validate_required([:url, :approved, :target_actor_id, :actor_id])
     |> unique_constraint(:target_actor_id, name: :followers_actor_target_actor_unique_index)
   end
+
+  # If there's a blank URL that's because we're doing the first insert
+  defp generate_url(%Ecto.Changeset{data: %Follower{url: nil}} = changeset) do
+    case fetch_change(changeset, :url) do
+      {:ok, _url} -> changeset
+      :error -> do_generate_url(changeset)
+    end
+  end
+
+  # Most time just go with the given URL
+  defp generate_url(%Ecto.Changeset{} = changeset), do: changeset
+
+  defp do_generate_url(%Ecto.Changeset{} = changeset) do
+    uuid = Ecto.UUID.generate()
+
+    changeset
+    |> put_change(
+      :url,
+      "#{MobilizonWeb.Endpoint.url()}/follow/#{uuid}"
+    )
+    |> put_change(
+      :id,
+      uuid
+    )
+  end
 end
diff --git a/lib/mobilizon/events/event.ex b/lib/mobilizon/events/event.ex
index fe100b3ea..d3be7e20b 100644
--- a/lib/mobilizon/events/event.ex
+++ b/lib/mobilizon/events/event.ex
@@ -91,7 +91,6 @@ defmodule Mobilizon.Events.Event do
       :title,
       :begins_on,
       :organizer_actor_id,
-      :category,
       :url,
       :uuid
     ])
diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex
index 7194dc89e..6371f06f1 100644
--- a/lib/mobilizon/events/events.ex
+++ b/lib/mobilizon/events/events.ex
@@ -32,7 +32,8 @@ defmodule Mobilizon.Events do
           :tracks,
           :tags,
           :participants,
-          :physical_address
+          :physical_address,
+          :picture
         ]
       )
       |> paginate(page, limit)
@@ -248,7 +249,8 @@ defmodule Mobilizon.Events do
           :tracks,
           :tags,
           :participants,
-          :physical_address
+          :physical_address,
+          :picture
         ]
       )
     )
diff --git a/lib/mobilizon_web/api/events.ex b/lib/mobilizon_web/api/events.ex
index 4207dcd4a..463667395 100644
--- a/lib/mobilizon_web/api/events.ex
+++ b/lib/mobilizon_web/api/events.ex
@@ -9,6 +9,8 @@ defmodule MobilizonWeb.API.Events do
   alias Mobilizon.Service.ActivityPub.Utils, as: ActivityPubUtils
   alias MobilizonWeb.API.Utils
 
+  @visibility %{"PUBLIC" => :public, "PRIVATE" => :private}
+
   @doc """
   Create an event
   """
diff --git a/lib/mobilizon_web/api/follows.ex b/lib/mobilizon_web/api/follows.ex
new file mode 100644
index 000000000..626c710b9
--- /dev/null
+++ b/lib/mobilizon_web/api/follows.ex
@@ -0,0 +1,51 @@
+defmodule MobilizonWeb.API.Follows do
+  @moduledoc """
+  Common API for following, unfollowing, accepting and rejecting stuff.
+  """
+
+  alias Mobilizon.Actors
+  alias Mobilizon.Actors.{Actor, Follower}
+  alias Mobilizon.Service.ActivityPub
+  require Logger
+
+  def follow(%Actor{} = follower, %Actor{} = followed) do
+    case ActivityPub.follow(follower, followed) do
+      {:ok, activity, _} ->
+        {:ok, activity}
+
+      e ->
+        Logger.warn("Error while following actor: #{inspect(e)}")
+        {:error, e}
+    end
+  end
+
+  def unfollow(%Actor{} = follower, %Actor{} = followed) do
+    case ActivityPub.unfollow(follower, followed) do
+      {:ok, activity, _} ->
+        {:ok, activity}
+
+      e ->
+        Logger.warn("Error while unfollowing actor: #{inspect(e)}")
+        {:error, e}
+    end
+  end
+
+  def accept(%Actor{} = follower, %Actor{} = followed) do
+    with %Follower{approved: false, id: follow_id, url: follow_url} = follow <-
+           Actor.following?(follower, followed),
+         activity_follow_url <- "#{MobilizonWeb.Endpoint.url()}/accept/follow/#{follow_id}",
+         data <-
+           ActivityPub.Utils.make_follow_data(followed, follower, follow_url),
+         {:ok, activity, _} <-
+           ActivityPub.accept(
+             %{to: [follower.url], actor: followed.url, object: data},
+             activity_follow_url
+           ),
+         {:ok, %Follower{approved: true}} <- Actors.update_follower(follow, %{"approved" => true}) do
+      {:ok, activity}
+    else
+      %Follower{approved: true} ->
+        {:error, "Follow already accepted"}
+    end
+  end
+end
diff --git a/lib/mobilizon_web/api/utils.ex b/lib/mobilizon_web/api/utils.ex
index 49d3cfb1a..6c983e447 100644
--- a/lib/mobilizon_web/api/utils.ex
+++ b/lib/mobilizon_web/api/utils.ex
@@ -9,7 +9,7 @@ defmodule MobilizonWeb.API.Utils do
   Determines the full audience based on mentions for a public audience
 
   Audience is:
-    * `to` : the mentionned actors, the eventual actor we're replying to and the public
+    * `to` : the mentioned actors, the eventual actor we're replying to and the public
     * `cc` : the actor's followers
   """
   @spec get_to_and_cc(Actor.t(), list(), map(), String.t()) :: {list(), list()}
@@ -72,7 +72,9 @@ defmodule MobilizonWeb.API.Utils do
     end
   end
 
-  def get_to_and_cc(_user, mentions, _inReplyTo, {:list, _}), do: {mentions, []}
+  def get_to_and_cc(_actor, mentions, _inReplyTo, {:list, _}) do
+    {mentions, []}
+  end
 
   #  def get_addressed_users(_, to) when is_list(to) do
   #    Actors.get(to)
@@ -138,7 +140,7 @@ defmodule MobilizonWeb.API.Utils do
            make_content_html(
              content,
              tags,
-             "text/plain"
+             "text/html"
            ),
          mentioned_users <- for({_, mentioned_user} <- mentions, do: mentioned_user.url),
          addressed_users <- get_addressed_users(mentioned_users, nil),
diff --git a/lib/mobilizon_web/controllers/activity_pub_controller.ex b/lib/mobilizon_web/controllers/activity_pub_controller.ex
index d091646ae..63e7d3fb9 100644
--- a/lib/mobilizon_web/controllers/activity_pub_controller.ex
+++ b/lib/mobilizon_web/controllers/activity_pub_controller.ex
@@ -14,6 +14,19 @@ defmodule MobilizonWeb.ActivityPubController do
 
   action_fallback(:errors)
 
+  plug(:relay_active? when action in [:relay])
+
+  def relay_active?(conn, _) do
+    if Mobilizon.CommonConfig.get([:instance, :allow_relay]) do
+      conn
+    else
+      conn
+      |> put_status(404)
+      |> json("Not found")
+      |> halt()
+    end
+  end
+
   def following(conn, %{"name" => name, "page" => page}) do
     with {page, ""} <- Integer.parse(page),
          %Actor{} = actor <- Actors.get_local_actor_by_name_with_everything(name) do
@@ -67,6 +80,7 @@ defmodule MobilizonWeb.ActivityPubController do
 
   # TODO: Ensure that this inbox is a recipient of the message
   def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
+    Logger.debug("Got something with valid signature inside inbox")
     Federator.enqueue(:incoming_ap_doc, params)
     json(conn, "ok")
   end
@@ -90,19 +104,35 @@ defmodule MobilizonWeb.ActivityPubController do
         "Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!"
       )
 
-      Logger.error(inspect(conn.req_headers))
+      Logger.debug(inspect(conn.req_headers))
     end
 
     json(conn, "error")
   end
 
+  def relay(conn, _params) do
+    with {status, actor} <-
+           Cachex.fetch(
+             :activity_pub,
+             "relay_actor",
+             &Mobilizon.Service.ActivityPub.Relay.get_actor/0
+           ),
+         true <- status in [:ok, :commit] do
+      conn
+      |> put_resp_header("content-type", "application/activity+json")
+      |> json(ActorView.render("actor.json", %{actor: actor}))
+    end
+  end
+
   def errors(conn, {:error, :not_found}) do
     conn
     |> put_status(404)
     |> json("Not found")
   end
 
-  def errors(conn, _e) do
+  def errors(conn, e) do
+    Logger.debug(inspect(e))
+
     conn
     |> put_status(500)
     |> json("Unknown Error")
diff --git a/lib/mobilizon_web/http_signature.ex b/lib/mobilizon_web/http_signature.ex
index 01aef6018..f6c1f2dba 100644
--- a/lib/mobilizon_web/http_signature.ex
+++ b/lib/mobilizon_web/http_signature.ex
@@ -10,7 +10,6 @@ defmodule MobilizonWeb.HTTPSignaturePlug do
   Plug to check HTTP Signatures on every incoming request
   """
 
-  alias Mobilizon.Service.HTTPSignatures
   import Plug.Conn
   require Logger
 
@@ -23,32 +22,30 @@ defmodule MobilizonWeb.HTTPSignaturePlug do
   end
 
   def call(conn, _opts) do
-    actor = conn.params["actor"]
-
-    Logger.debug(fn ->
-      "Checking sig for #{actor}"
-    end)
-
     [signature | _] = get_req_header(conn, "signature")
 
-    cond do
-      String.contains?(signature, actor) ->
-        conn =
-          conn
-          |> put_req_header(
-            "(request-target)",
-            String.downcase("#{conn.method}") <> " #{conn.request_path}"
-          )
-
-        assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
-
-      signature ->
-        Logger.debug("Signature not from actor")
-        assign(conn, :valid_signature, false)
-
-      true ->
-        Logger.debug("No signature header!")
+    if signature do
+      # set (request-target) header to the appropriate value
+      # we also replace the digest header with the one we computed
+      conn =
         conn
+        |> put_req_header(
+          "(request-target)",
+          String.downcase("#{conn.method}") <> " #{conn.request_path}"
+        )
+
+      conn =
+        if conn.assigns[:digest] do
+          conn
+          |> put_req_header("digest", conn.assigns[:digest])
+        else
+          conn
+        end
+
+      assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
+    else
+      Logger.debug("No signature header!")
+      conn
     end
   end
 end
diff --git a/lib/mobilizon_web/router.ex b/lib/mobilizon_web/router.ex
index e70a0ccbb..2ecd44af4 100644
--- a/lib/mobilizon_web/router.ex
+++ b/lib/mobilizon_web/router.ex
@@ -18,6 +18,10 @@ defmodule MobilizonWeb.Router do
     plug(MobilizonWeb.HTTPSignaturePlug)
   end
 
+  pipeline :relay do
+    plug(:accepts, ["activity-json", "json"])
+  end
+
   pipeline :activity_pub do
     plug(:accepts, ["activity-json"])
   end
@@ -97,6 +101,13 @@ defmodule MobilizonWeb.Router do
     post("/inbox", ActivityPubController, :inbox)
   end
 
+  scope "/relay", MobilizonWeb do
+    pipe_through(:relay)
+
+    get("/", ActivityPubController, :relay)
+    post("/inbox", ActivityPubController, :inbox)
+  end
+
   scope "/proxy/", MobilizonWeb do
     pipe_through(:remote_media)
 
diff --git a/lib/mobilizon_web/schema/event.ex b/lib/mobilizon_web/schema/event.ex
index aff8bc835..96f8bea30 100644
--- a/lib/mobilizon_web/schema/event.ex
+++ b/lib/mobilizon_web/schema/event.ex
@@ -131,7 +131,7 @@ defmodule MobilizonWeb.Schema.EventType do
       arg(:online_address, :string)
       arg(:phone_address, :string)
       arg(:organizer_actor_id, non_null(:id))
-      arg(:category, non_null(:string))
+      arg(:category, :string)
       arg(:physical_address, :address_input)
 
       resolve(&Event.create_event/3)
diff --git a/lib/mobilizon_web/views/activity_pub/actor_view.ex b/lib/mobilizon_web/views/activity_pub/actor_view.ex
index f2f772761..2d57cc278 100644
--- a/lib/mobilizon_web/views/activity_pub/actor_view.ex
+++ b/lib/mobilizon_web/views/activity_pub/actor_view.ex
@@ -12,12 +12,12 @@ defmodule MobilizonWeb.ActivityPub.ActorView do
     public_key = Mobilizon.Service.ActivityPub.Utils.pem_to_public_key_pem(actor.keys)
 
     %{
-      "id" => Actor.build_url(actor.preferred_username, :page),
-      "type" => "Person",
-      "following" => Actor.build_url(actor.preferred_username, :following),
-      "followers" => Actor.build_url(actor.preferred_username, :followers),
-      "inbox" => Actor.build_url(actor.preferred_username, :inbox),
-      "outbox" => Actor.build_url(actor.preferred_username, :outbox),
+      "id" => actor.url,
+      "type" => to_string(actor.type),
+      "following" => actor.following_url,
+      "followers" => actor.followers_url,
+      "inbox" => actor.inbox_url,
+      "outbox" => actor.outbox_url,
       "preferredUsername" => actor.preferred_username,
       "name" => actor.name,
       "summary" => actor.summary,
diff --git a/lib/mobilizon_web/views/error_view.ex b/lib/mobilizon_web/views/error_view.ex
index 3a252a8bf..79d58e6d7 100644
--- a/lib/mobilizon_web/views/error_view.ex
+++ b/lib/mobilizon_web/views/error_view.ex
@@ -31,8 +31,8 @@ defmodule MobilizonWeb.ErrorView do
   # template is found, let's render it as 500
   def template_not_found(template, assigns) do
     require Logger
-    Logger.error("Template not found")
-    Logger.error(inspect(template))
+    Logger.warn("Template not found")
+    Logger.debug(inspect(template))
     render("500.html", assigns)
   end
 end
diff --git a/lib/mobilizon_web/views/page_view.ex b/lib/mobilizon_web/views/page_view.ex
index 767dc877e..9064aa4b9 100644
--- a/lib/mobilizon_web/views/page_view.ex
+++ b/lib/mobilizon_web/views/page_view.ex
@@ -46,24 +46,8 @@ defmodule MobilizonWeb.PageView do
   end
 
   def render("event.activity-json", %{conn: %{assigns: %{object: event}}}) do
-    event = Mobilizon.Service.ActivityPub.Converters.Event.model_to_as(event)
-    {:ok, html, []} = Earmark.as_html(event["summary"])
-
-    %{
-      "type" => "Event",
-      "attributedTo" => event["actor"],
-      "id" => event["id"],
-      "name" => event["title"],
-      "category" => event["category"],
-      "content" => html,
-      "source" => %{
-        "content" => event["summary"],
-        "mediaType" => "text/markdown"
-      },
-      "mediaType" => "text/html",
-      "published" => event["publish_at"],
-      "updated" => event["updated_at"]
-    }
+    event
+    |> Mobilizon.Service.ActivityPub.Converters.Event.model_to_as()
     |> Map.merge(Utils.make_json_ld_header())
   end
 
diff --git a/lib/service/activity_pub/activity_pub.ex b/lib/service/activity_pub/activity_pub.ex
index 483a7a14f..48f69ca3d 100644
--- a/lib/service/activity_pub/activity_pub.ex
+++ b/lib/service/activity_pub/activity_pub.ex
@@ -21,10 +21,11 @@ defmodule Mobilizon.Service.ActivityPub do
   alias Mobilizon.Actors.Follower
 
   alias Mobilizon.Service.Federator
-  alias Mobilizon.Service.HTTPSignatures
+  alias Mobilizon.Service.HTTPSignatures.Signature
 
   require Logger
   import Mobilizon.Service.ActivityPub.Utils
+  import Mobilizon.Service.ActivityPub.Visibility
 
   @doc """
   Get recipients for an activity or object
@@ -42,10 +43,6 @@ defmodule Mobilizon.Service.ActivityPub do
   def insert(map, local \\ true) when is_map(map) do
     with map <- lazy_put_activity_defaults(map),
          {:ok, object} <- insert_full_object(map) do
-      object_id = if is_map(map["object"]), do: map["object"]["id"], else: map["id"]
-
-      map = if local, do: Map.put(map, "id", "#{object_id}/activity"), else: map
-
       activity = %Activity{
         data: map,
         local: local,
@@ -94,7 +91,7 @@ defmodule Mobilizon.Service.ActivityPub do
          {:ok, _activity, %{url: object_url} = _object} <- Transmogrifier.handle_incoming(params) do
       case data["type"] do
         "Event" ->
-          {:ok, Events.get_event_by_url!(object_url)}
+          {:ok, Events.get_event_full_by_url!(object_url)}
 
         "Note" ->
           {:ok, Events.get_comment_full_from_url!(object_url)}
@@ -107,15 +104,17 @@ defmodule Mobilizon.Service.ActivityPub do
       end
     else
       {:existing_event, %Event{url: event_url}} ->
-        {:ok, Events.get_event_by_url!(event_url)}
+        {:ok, Events.get_event_full_by_url!(event_url)}
 
       {:existing_comment, %Comment{url: comment_url}} ->
         {:ok, Events.get_comment_full_from_url!(comment_url)}
 
-      {:existing_actor, %Actor{url: actor_url}} ->
+      {:existing_actor, {:ok, %Actor{url: actor_url}}} ->
         {:ok, Actors.get_actor_by_url!(actor_url, true)}
 
       e ->
+        require Logger
+        Logger.error(inspect(e))
         {:error, e}
     end
   end
@@ -137,24 +136,40 @@ defmodule Mobilizon.Service.ActivityPub do
              %{to: to, actor: actor, published: published, object: object},
              additional
            ),
-         :ok <- Logger.debug(inspect(create_data)),
          {:ok, activity, object} <- insert(create_data, local),
          :ok <- maybe_federate(activity) do
       # {:ok, actor} <- Actors.increase_event_count(actor) do
       {:ok, activity, object}
     else
       err ->
-        Logger.error("Something went wrong")
-        Logger.error(inspect(err))
+        Logger.error("Something went wrong while creating an activity")
+        Logger.debug(inspect(err))
         err
     end
   end
 
-  def accept(%{to: to, actor: actor, object: object} = params) do
+  def accept(%{to: to, actor: actor, object: object} = params, activity_follow_id \\ nil) do
     # only accept false as false value
     local = !(params[:local] == false)
 
-    with data <- %{"to" => to, "type" => "Accept", "actor" => actor, "object" => object},
+    with data <- %{
+           "to" => to,
+           "type" => "Accept",
+           "actor" => actor,
+           "object" => object,
+           "id" => activity_follow_id || get_url(object) <> "/activity"
+         },
+         {:ok, activity, object} <- insert(data, local),
+         :ok <- maybe_federate(activity) do
+      {:ok, activity, object}
+    end
+  end
+
+  def reject(%{to: to, actor: actor, object: object} = params) do
+    # only accept false as false value
+    local = !(params[:local] == false)
+
+    with data <- %{"to" => to, "type" => "Reject", "actor" => actor.url, "object" => object},
          {:ok, activity, object} <- insert(data, local),
          :ok <- maybe_federate(activity) do
       {:ok, activity, object}
@@ -168,6 +183,7 @@ defmodule Mobilizon.Service.ActivityPub do
     with data <- %{
            "to" => to,
            "cc" => cc,
+           "id" => object["url"],
            "type" => "Update",
            "actor" => actor,
            "object" => object
@@ -215,55 +231,56 @@ defmodule Mobilizon.Service.ActivityPub do
   #   end
   # end
 
-  # def announce(
-  #       %Actor{} = actor,
-  #       object,
-  #       activity_id \\ nil,
-  #       local \\ true
-  #     ) do
-  #   #with true <- is_public?(object),
-  #        with announce_data <- make_announce_data(actor, object, activity_id),
-  #        {:ok, activity, object} <- insert(announce_data, local),
-  #       #  {:ok, object} <- add_announce_to_object(activity, object),
-  #        :ok <- maybe_federate(activity) do
-  #     {:ok, activity, object}
-  #   else
-  #     error -> {:error, error}
-  #   end
-  # end
+  def announce(
+        %Actor{} = actor,
+        object,
+        activity_id \\ nil,
+        local \\ true,
+        public \\ true
+      ) do
+    with true <- is_public?(object),
+         announce_data <- make_announce_data(actor, object, activity_id, public),
+         {:ok, activity, object} <- insert(announce_data, local),
+         :ok <- maybe_federate(activity) do
+      {:ok, activity, object}
+    else
+      error ->
+        {:error, error}
+    end
+  end
 
-  # def unannounce(
-  #       %Actor{} = actor,
-  #       object,
-  #       activity_id \\ nil,
-  #       local \\ true
-  #     ) do
-  #   with %Activity{} = announce_activity <- get_existing_announce(actor.ap_id, object),
-  #        unannounce_data <- make_unannounce_data(actor, announce_activity, activity_id),
-  #        {:ok, unannounce_activity, _object} <- insert(unannounce_data, local),
-  #        :ok <- maybe_federate(unannounce_activity),
-  #        {:ok, _activity} <- Repo.delete(announce_activity),
-  #        {:ok, object} <- remove_announce_from_object(announce_activity, object) do
-  #     {:ok, unannounce_activity, object}
-  #   else
-  #     _e -> {:ok, object}
-  #   end
-  # end
+  def unannounce(
+        %Actor{} = actor,
+        object,
+        activity_id \\ nil,
+        cancelled_activity_id \\ nil,
+        local \\ true
+      ) do
+    with announce_activity <- make_announce_data(actor, object, cancelled_activity_id),
+         unannounce_data <- make_unannounce_data(actor, announce_activity, activity_id),
+         {:ok, unannounce_activity, _object} <- insert(unannounce_data, local),
+         :ok <- maybe_federate(unannounce_activity) do
+      {:ok, unannounce_activity, object}
+    else
+      _e -> {:ok, object}
+    end
+  end
 
   @doc """
   Make an actor follow another
   """
   def follow(%Actor{} = follower, %Actor{} = followed, activity_id \\ nil, local \\ true) do
-    with {:ok, %Follower{id: follow_id}} <- Actor.follow(followed, follower, true),
+    with {:ok, %Follower{url: follow_url}} <-
+           Actor.follow(followed, follower, activity_id, false),
          activity_follow_id <-
-           activity_id || "#{MobilizonWeb.Endpoint.url()}/follow/#{follow_id}/activity",
+           activity_id || follow_url,
          data <- make_follow_data(followed, follower, activity_follow_id),
          {:ok, activity, object} <- insert(data, local),
          :ok <- maybe_federate(activity) do
       {:ok, activity, object}
     else
-      {err, _} when err in [:already_following, :suspended] ->
-        {:error, err}
+      {:error, err, msg} when err in [:already_following, :suspended] ->
+        {:error, msg}
     end
   end
 
@@ -271,18 +288,26 @@ defmodule Mobilizon.Service.ActivityPub do
   Make an actor unfollow another
   """
   @spec unfollow(Actor.t(), Actor.t(), String.t(), boolean()) :: {:ok, map()} | any()
-  def unfollow(%Actor{} = followed, %Actor{} = follower, activity_id \\ nil, local \\ true) do
+  def unfollow(%Actor{} = follower, %Actor{} = followed, activity_id \\ nil, local \\ true) do
     with {:ok, %Follower{id: follow_id}} <- Actor.unfollow(followed, follower),
          # We recreate the follow activity
-         data <- make_follow_data(followed, follower, follow_id),
+         data <-
+           make_follow_data(
+             followed,
+             follower,
+             "#{MobilizonWeb.Endpoint.url()}/follow/#{follow_id}/activity"
+           ),
          {:ok, follow_activity, _object} <- insert(data, local),
-         unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
+         activity_unfollow_id <-
+           activity_id || "#{MobilizonWeb.Endpoint.url()}/unfollow/#{follow_id}/activity",
+         unfollow_data <-
+           make_unfollow_data(follower, followed, follow_activity, activity_unfollow_id),
          {:ok, activity, object} <- insert(unfollow_data, local),
          :ok <- maybe_federate(activity) do
       {:ok, activity, object}
     else
       err ->
-        Logger.error(inspect(err))
+        Logger.debug("Error while unfollowing an actor #{inspect(err)}")
         err
     end
   end
@@ -294,7 +319,8 @@ defmodule Mobilizon.Service.ActivityPub do
       "type" => "Delete",
       "actor" => actor.url,
       "object" => url,
-      "to" => [actor.url <> "/followers", "https://www.w3.org/ns/activitystreams#Public"]
+      "to" => [actor.url <> "/followers", "https://www.w3.org/ns/activitystreams#Public"],
+      "id" => url <> "/delete"
     }
 
     with {:ok, _} <- Events.delete_event(event),
@@ -309,6 +335,7 @@ defmodule Mobilizon.Service.ActivityPub do
       "type" => "Delete",
       "actor" => actor.url,
       "object" => url,
+      "id" => url <> "/delete",
       "to" => [actor.url <> "/followers", "https://www.w3.org/ns/activitystreams#Public"]
     }
 
@@ -324,6 +351,7 @@ defmodule Mobilizon.Service.ActivityPub do
       "type" => "Delete",
       "actor" => url,
       "object" => url,
+      "id" => url <> "/delete",
       "to" => [url <> "/followers", "https://www.w3.org/ns/activitystreams#Public"]
     }
 
@@ -366,11 +394,11 @@ defmodule Mobilizon.Service.ActivityPub do
 
       # Request returned 410
       {:error, :actor_deleted} ->
+        Logger.info("Actor was deleted")
         {:error, :actor_deleted}
 
       e ->
-        Logger.error("Failed to make actor from url")
-        Logger.error(inspect(e))
+        Logger.warn("Failed to make actor from url")
         {:error, e}
     end
   end
@@ -414,10 +442,18 @@ defmodule Mobilizon.Service.ActivityPub do
   """
   def publish(actor, activity) do
     Logger.debug("Publishing an activity")
+    Logger.debug(inspect(activity))
+
+    public = is_public?(activity)
+
+    if public && Mobilizon.CommonConfig.get([:instance, :allow_relay]) do
+      Logger.info(fn -> "Relaying #{activity.data["id"]} out" end)
+      Mobilizon.Service.ActivityPub.Relay.publish(activity)
+    end
 
     followers =
       if actor.followers_url in activity.recipients do
-        Actor.get_full_followers(actor) |> Enum.filter(fn follower -> is_nil(follower.domain) end)
+        Actor.get_full_external_followers(actor)
       else
         []
       end
@@ -448,15 +484,16 @@ defmodule Mobilizon.Service.ActivityPub do
     Logger.info("Federating #{id} to #{inbox}")
     %URI{host: host, path: path} = URI.parse(inbox)
 
-    digest = HTTPSignatures.build_digest(json)
-    date = HTTPSignatures.generate_date_header()
-    request_target = HTTPSignatures.generate_request_target("POST", path)
+    digest = Signature.build_digest(json)
+    date = Signature.generate_date_header()
+    # request_target = Signature.generate_request_target("POST", path)
 
     signature =
-      HTTPSignatures.sign(actor, %{
+      Signature.sign(actor, %{
         host: host,
         "content-length": byte_size(json),
-        "(request-target)": request_target,
+        # TODO : Look me up in depth why Pleroma handles this inside lib/mobilizon_web/http_signature.ex
+        # "(request-target)": request_target,
         digest: digest,
         date: date
       })
@@ -478,20 +515,27 @@ defmodule Mobilizon.Service.ActivityPub do
   @spec fetch_and_prepare_actor_from_url(String.t()) :: {:ok, struct()} | {:error, atom()} | any()
   defp fetch_and_prepare_actor_from_url(url) do
     Logger.debug("Fetching and preparing actor from url")
+    Logger.debug(inspect(url))
 
-    with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <-
-           HTTPoison.get(url, [Accept: "application/activity+json"], follow_redirect: true),
-         {:ok, data} <- Jason.decode(body) do
-      actor_data_from_actor_object(data)
-    else
-      # Actor is gone, probably deleted
-      {:ok, %HTTPoison.Response{status_code: 410}} ->
-        {:error, :actor_deleted}
+    res =
+      with %HTTPoison.Response{status_code: 200, body: body} <-
+             HTTPoison.get!(url, [Accept: "application/activity+json"], follow_redirect: true),
+           :ok <- Logger.debug("response okay, now decoding json"),
+           {:ok, data} <- Jason.decode(body) do
+        Logger.debug("Got activity+json response at actor's endpoint, now converting data")
+        actor_data_from_actor_object(data)
+      else
+        # Actor is gone, probably deleted
+        {:ok, %HTTPoison.Response{status_code: 410}} ->
+          Logger.info("Response HTTP 410")
+          {:error, :actor_deleted}
 
-      e ->
-        Logger.error("Could not decode actor at fetch #{url}, #{inspect(e)}")
-        e
-    end
+        e ->
+          Logger.warn("Could not decode actor at fetch #{url}, #{inspect(e)}")
+          {:error, e}
+      end
+
+    res
   end
 
   @doc """
diff --git a/lib/service/activity_pub/converter.ex b/lib/service/activity_pub/converter.ex
index 4af0b3bd0..858859db2 100644
--- a/lib/service/activity_pub/converter.ex
+++ b/lib/service/activity_pub/converter.ex
@@ -7,3 +7,10 @@ defmodule Mobilizon.Service.ActivityPub.Converter do
   @callback as_to_model_data(map()) :: map()
   @callback model_to_as(struct()) :: map()
 end
+
+defprotocol Mobilizon.Service.ActivityPub.Convertible do
+  @type activitystreams :: map()
+
+  @spec model_to_as(t) :: activitystreams
+  def model_to_as(convertible)
+end
diff --git a/lib/service/activity_pub/converters/actor.ex b/lib/service/activity_pub/converters/actor.ex
index 8e444a6fd..853173867 100644
--- a/lib/service/activity_pub/converters/actor.ex
+++ b/lib/service/activity_pub/converters/actor.ex
@@ -45,3 +45,9 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Actor do
     }
   end
 end
+
+defimpl Mobilizon.Service.ActivityPub.Convertible, for: Mobilizon.Actors.Actor do
+  alias Mobilizon.Service.ActivityPub.Converters.Actor, as: ActorConverter
+
+  defdelegate model_to_as(actor), to: ActorConverter
+end
diff --git a/lib/service/activity_pub/converters/address.ex b/lib/service/activity_pub/converters/address.ex
index d6d0cc1c3..1d5ae0831 100644
--- a/lib/service/activity_pub/converters/address.ex
+++ b/lib/service/activity_pub/converters/address.ex
@@ -52,7 +52,29 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Address do
   """
   @impl Converter
   @spec model_to_as(AddressModel.t()) :: map()
-  def model_to_as(%AddressModel{} = _address) do
-    nil
+  def model_to_as(%AddressModel{} = address) do
+    res = %{
+      "type" => "Place",
+      "name" => address.description,
+      "id" => address.url,
+      "address" => %{
+        "type" => "PostalAddress",
+        "streetAddress" => address.street,
+        "postalCode" => address.postal_code,
+        "addressLocality" => address.locality,
+        "addressRegion" => address.region,
+        "addressCountry" => address.country
+      }
+    }
+
+    if is_nil(address.geom) do
+      res
+    else
+      Map.put(res, "geo", %{
+        "type" => "GeoCoordinates",
+        "latitude" => address.geom.coordinates |> elem(0),
+        "longitude" => address.geom.coordinates |> elem(1)
+      })
+    end
   end
 end
diff --git a/lib/service/activity_pub/converters/comment.ex b/lib/service/activity_pub/converters/comment.ex
index 3412aefcc..1513dff3c 100644
--- a/lib/service/activity_pub/converters/comment.ex
+++ b/lib/service/activity_pub/converters/comment.ex
@@ -84,7 +84,7 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Comment do
       "actor" => comment.actor.url,
       "attributedTo" => comment.actor.url,
       "uuid" => comment.uuid,
-      "id" => Routes.page_url(Endpoint, :comment, comment.uuid)
+      "id" => comment.url
     }
 
     if comment.in_reply_to_comment do
@@ -94,3 +94,9 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Comment do
     end
   end
 end
+
+defimpl Mobilizon.Service.ActivityPub.Convertible, for: Mobilizon.Events.Comment do
+  alias Mobilizon.Service.ActivityPub.Converters.Comment, as: CommentConverter
+
+  defdelegate model_to_as(comment), to: CommentConverter
+end
diff --git a/lib/service/activity_pub/converters/event.ex b/lib/service/activity_pub/converters/event.ex
index 1c6a64500..0b069f90b 100644
--- a/lib/service/activity_pub/converters/event.ex
+++ b/lib/service/activity_pub/converters/event.ex
@@ -10,6 +10,8 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Event do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events.Event, as: EventModel
   alias Mobilizon.Service.ActivityPub.Converter
+  alias Mobilizon.Service.ActivityPub.Converters.Address, as: AddressConverter
+  alias Mobilizon.Service.ActivityPub.Utils
   alias Mobilizon.Events
   alias Mobilizon.Events.Tag
   alias Mobilizon.Addresses
@@ -26,6 +28,7 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Event do
   @spec as_to_model_data(map()) :: map()
   def as_to_model_data(object) do
     Logger.debug("event as_to_model_data")
+    Logger.debug(inspect(object))
 
     with {:actor, {:ok, %Actor{id: actor_id}}} <-
            {:actor, Actors.get_actor_by_url(object["actor"])},
@@ -99,6 +102,8 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Event do
   end
 
   defp fetch_tags(tags) do
+    Logger.debug("fetching tags")
+
     Enum.reduce(tags, [], fn tag, acc ->
       with true <- tag["type"] == "Hashtag",
            {:ok, %Tag{} = tag} <- Events.get_or_create_tag(tag) do
@@ -110,23 +115,62 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Event do
     end)
   end
 
+  defp build_tags(tags) do
+    Enum.map(tags, fn %Tag{} = tag ->
+      %{
+        "href" => MobilizonWeb.Endpoint.url() <> "/tags/#{tag.slug}",
+        "name" => "##{tag.title}",
+        "type" => "Hashtag"
+      }
+    end)
+  end
+
   @doc """
   Convert an event struct to an ActivityStream representation
   """
   @impl Converter
   @spec model_to_as(EventModel.t()) :: map()
   def model_to_as(%EventModel{} = event) do
-    %{
+    to =
+      if event.visibility == :public,
+        do: ["https://www.w3.org/ns/activitystreams#Public"],
+        else: [event.organizer_actor.followers_url]
+
+    res = %{
       "type" => "Event",
-      "to" => ["https://www.w3.org/ns/activitystreams#Public"],
-      "title" => event.title,
+      "to" => to,
+      "cc" => [],
+      "attributedTo" => event.organizer_actor.url,
+      "name" => event.title,
       "actor" => event.organizer_actor.url,
       "uuid" => event.uuid,
       "category" => event.category,
-      "summary" => event.description,
-      "publish_at" => (event.publish_at || event.inserted_at) |> DateTime.to_iso8601(),
-      "updated_at" => event.updated_at |> DateTime.to_iso8601(),
+      "content" => event.description,
+      "publish_at" => (event.publish_at || event.inserted_at) |> date_to_string(),
+      "updated_at" => event.updated_at |> date_to_string(),
+      "mediaType" => "text/html",
+      "startTime" => event.begins_on |> date_to_string(),
+      "endTime" => event.ends_on |> date_to_string(),
+      "tag" => event.tags |> build_tags(),
       "id" => event.url
     }
+
+    res =
+      if is_nil(event.physical_address),
+        do: res,
+        else: Map.put(res, "location", AddressConverter.model_to_as(event.physical_address))
+
+    if is_nil(event.picture),
+      do: res,
+      else: Map.put(res, "attachment", [Utils.make_picture_data(event.picture)])
   end
+
+  defp date_to_string(nil), do: nil
+  defp date_to_string(date), do: DateTime.to_iso8601(date)
+end
+
+defimpl Mobilizon.Service.ActivityPub.Convertible, for: Mobilizon.Events.Event do
+  alias Mobilizon.Service.ActivityPub.Converters.Event, as: EventConverter
+
+  defdelegate model_to_as(event), to: EventConverter
 end
diff --git a/lib/service/activity_pub/relay.ex b/lib/service/activity_pub/relay.ex
new file mode 100644
index 000000000..933644c68
--- /dev/null
+++ b/lib/service/activity_pub/relay.ex
@@ -0,0 +1,88 @@
+# Portions of this file are derived from Pleroma:
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social>
+# SPDX-License-Identifier: AGPL-3.0-only
+# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/relay.ex
+
+defmodule Mobilizon.Service.ActivityPub.Relay do
+  @moduledoc """
+  Handles following and unfollowing relays and instances
+  """
+
+  alias Mobilizon.Activity
+  alias Mobilizon.Actors
+  alias Mobilizon.Actors.Actor
+  alias Mobilizon.Service.ActivityPub
+  alias MobilizonWeb.API.Follows
+  require Logger
+
+  def get_actor do
+    with {:ok, %Actor{} = actor} <-
+           Actors.get_or_create_service_actor_by_url("#{MobilizonWeb.Endpoint.url()}/relay") do
+      actor
+    end
+  end
+
+  def follow(target_instance) do
+    with %Actor{} = local_actor <- get_actor(),
+         {:ok, %Actor{} = target_actor} <- Actors.get_or_fetch_by_url(target_instance),
+         {:ok, activity} <- Follows.follow(local_actor, target_actor) do
+      Logger.info("Relay: followed instance #{target_instance}; id=#{activity.data["id"]}")
+      {:ok, activity}
+    else
+      e ->
+        Logger.warn("Error while following remote instance: #{inspect(e)}")
+        {:error, e}
+    end
+  end
+
+  def unfollow(target_instance) do
+    with %Actor{} = local_actor <- get_actor(),
+         {:ok, %Actor{} = target_actor} <- Actors.get_or_fetch_by_url(target_instance),
+         {:ok, activity} <- Follows.unfollow(local_actor, target_actor) do
+      Logger.info("Relay: unfollowed instance #{target_instance}: id=#{activity.data["id"]}")
+      {:ok, activity}
+    else
+      e ->
+        Logger.warn("Error while unfollowing remote instance: #{inspect(e)}")
+        {:error, e}
+    end
+  end
+
+  def accept(target_instance) do
+    with %Actor{} = local_actor <- get_actor(),
+         {:ok, %Actor{} = target_actor} <- Actors.get_or_fetch_by_url(target_instance),
+         {:ok, activity} <- Follows.accept(target_actor, local_actor) do
+      {:ok, activity}
+    end
+  end
+
+  #  def reject(target_instance) do
+  #    with %Actor{} = local_actor <- get_actor(),
+  #         {:ok, %Actor{} = target_actor} <- Actors.get_or_fetch_by_url(target_instance),
+  #         {:ok, activity} <- Follows.reject(target_actor, local_actor) do
+  #      {:ok, activity}
+  #    end
+  #  end
+
+  @doc """
+  Publish an activity to all relays following this instance
+  """
+  def publish(%Activity{data: %{"object" => object}} = _activity) do
+    with %Actor{id: actor_id} = actor <- get_actor(),
+         {:ok, object} <-
+           Mobilizon.Service.ActivityPub.Transmogrifier.fetch_obj_helper_as_activity_streams(
+             object
+           ) do
+      ActivityPub.announce(actor, object, "#{object["id"]}/announces/#{actor_id}", true, false)
+    else
+      e ->
+        Logger.error("Error while getting local instance actor: #{inspect(e)}")
+    end
+  end
+
+  def publish(err) do
+    Logger.error("Tried to publish a bad activity")
+    Logger.debug(inspect(err))
+    nil
+  end
+end
diff --git a/lib/service/activity_pub/transmogrifier.ex b/lib/service/activity_pub/transmogrifier.ex
index d2022b78f..75c0bcc73 100644
--- a/lib/service/activity_pub/transmogrifier.ex
+++ b/lib/service/activity_pub/transmogrifier.ex
@@ -8,11 +8,12 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   A module to handle coding from internal to wire ActivityPub and back.
   """
   alias Mobilizon.Actors
-  alias Mobilizon.Actors.Actor
+  alias Mobilizon.Actors.{Actor, Follower}
   alias Mobilizon.Events
   alias Mobilizon.Events.{Event, Comment}
   alias Mobilizon.Service.ActivityPub
   alias Mobilizon.Service.ActivityPub.Utils
+  alias Mobilizon.Service.ActivityPub.Visibility
 
   require Logger
 
@@ -45,7 +46,8 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
     |> Map.put("actor", object["attributedTo"])
     |> fix_attachments
     |> fix_in_reply_to
-    |> fix_tag
+
+    # |> fix_tag
   end
 
   def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object)
@@ -69,8 +71,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
 
   def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object)
       when not is_nil(in_reply_to) do
-    Logger.error("inReplyTo ID seem incorrect")
-    Logger.error(inspect(in_reply_to))
+    Logger.warn("inReplyTo ID seem incorrect: #{inspect(in_reply_to)}")
     do_fix_in_reply_to("", object)
   end
 
@@ -87,7 +88,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
         object
 
       e ->
-        Logger.error("Couldn't fetch #{in_reply_to_id} #{inspect(e)}")
+        Logger.warn("Couldn't fetch #{in_reply_to_id} #{inspect(e)}")
         object
     end
   end
@@ -116,6 +117,9 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
     |> Map.put("tag", combined)
   end
 
+  def handle_incoming(%{"id" => nil}), do: :error
+  def handle_incoming(%{"id" => ""}), do: :error
+
   def handle_incoming(%{"type" => "Flag"} = data) do
     with params <- Mobilizon.Service.ActivityPub.Converters.Flag.as_to_model(data) do
       params = %{
@@ -186,13 +190,69 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
     with {:ok, %Actor{} = followed} <- Actors.get_or_fetch_by_url(followed, true),
          {:ok, %Actor{} = follower} <- Actors.get_or_fetch_by_url(follower),
          {:ok, activity, object} <- ActivityPub.follow(follower, followed, id, false) do
-      ActivityPub.accept(%{to: [follower.url], actor: followed.url, object: data, local: true})
-
       {:ok, activity, object}
     else
       e ->
-        Logger.error("Unable to handle Follow activity")
-        Logger.error(inspect(e))
+        Logger.warn("Unable to handle Follow activity #{inspect(e)}")
+        :error
+    end
+  end
+
+  # TODO : Handle object being a Link
+  def handle_incoming(
+        %{
+          "type" => "Accept",
+          "object" => follow_object,
+          "actor" => _actor,
+          "id" => _id
+        } = data
+      ) do
+    with followed_actor_url <- get_actor(data),
+         {:ok, %Actor{} = followed} <- Actors.get_or_fetch_by_url(followed_actor_url),
+         {:ok, %Follower{approved: false, actor: follower, id: follow_id} = follow} <-
+           get_follow(follow_object),
+         {:ok, activity, _} <-
+           ActivityPub.accept(
+             %{
+               to: [follower.url],
+               actor: followed.url,
+               object: follow_object,
+               local: false
+             },
+             "#{MobilizonWeb.Endpoint.url()}/accept/follow/#{follow_id}"
+           ),
+         {:ok, %Follower{approved: true}} <- Actors.update_follower(follow, %{"approved" => true}) do
+      {:ok, activity, follow}
+    else
+      {:ok, %Follower{approved: true} = _follow} ->
+        {:error, "Follow already accepted"}
+
+      e ->
+        Logger.warn("Unable to process Accept Follow activity #{inspect(e)}")
+        :error
+    end
+  end
+
+  def handle_incoming(
+        %{"type" => "Reject", "object" => follow_object, "actor" => _actor, "id" => _id} = data
+      ) do
+    with followed_actor_url <- get_actor(data),
+         {:ok, %Actor{} = followed} <- Actors.get_or_fetch_by_url(followed_actor_url),
+         {:ok, %Follower{approved: false, actor: follower, id: follow_id} = follow} <-
+           get_follow(follow_object),
+         {:ok, activity, object} <-
+           ActivityPub.reject(%{
+             to: [follower.url],
+             type: "Reject",
+             actor: followed,
+             object: follow_object,
+             local: false
+           }),
+         {:ok, _follower} <- Actor.unfollow(followed, follower) do
+      {:ok, activity, object}
+    else
+      e ->
+        Logger.debug(inspect(e))
         :error
     end
   end
@@ -211,19 +271,21 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   #    end
   #  end
   # #
-  # def handle_incoming(
-  #       %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data
-  #     ) do
-  #   with actor <- get_actor(data),
-  #        {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor),
-  #        {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
-  #        {:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false) do
-  #     {:ok, activity}
-  #   else
-  #     e -> Logger.error(inspect e)
-  #       :error
-  #   end
-  # end
+  def handle_incoming(
+        %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data
+      ) do
+    with actor <- get_actor(data),
+         {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor),
+         {:ok, object} <- fetch_obj_helper_as_activity_streams(object_id),
+         public <- Visibility.is_public?(data),
+         {:ok, activity, object} <- ActivityPub.announce(actor, object, id, false, public) do
+      {:ok, activity, object}
+    else
+      e ->
+        Logger.debug(inspect(e))
+        :error
+    end
+  end
 
   def handle_incoming(
         %{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => _actor_id} =
@@ -245,28 +307,33 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
         })
 
       e ->
-        Logger.error(inspect(e))
+        Logger.debug(inspect(e))
         :error
     end
   end
 
-  # def handle_incoming(
-  #       %{
-  #         "type" => "Undo",
-  #         "object" => %{"type" => "Announce", "object" => object_id},
-  #         "actor" => actor,
-  #         "id" => id
-  #       } = data
-  #     ) do
-  #   with actor <- get_actor(data),
-  #        {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor),
-  #        {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
-  #        {:ok, activity, _} <- ActivityPub.unannounce(actor, object, id, false) do
-  #     {:ok, activity}
-  #   else
-  #     _e -> :error
-  #   end
-  # end
+  def handle_incoming(
+        %{
+          "type" => "Undo",
+          "object" => %{
+            "type" => "Announce",
+            "object" => object_id,
+            "id" => cancelled_activity_id
+          },
+          "actor" => actor,
+          "id" => id
+        } = data
+      ) do
+    with actor <- get_actor(data),
+         {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor),
+         {:ok, object} <- fetch_obj_helper_as_activity_streams(object_id),
+         {:ok, activity, object} <-
+           ActivityPub.unannounce(actor, object, id, cancelled_activity_id, false) do
+      {:ok, activity, object}
+    else
+      _e -> :error
+    end
+  end
 
   def handle_incoming(
         %{
@@ -278,12 +345,11 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
       ) do
     with {:ok, %Actor{domain: nil} = followed} <- Actors.get_actor_by_url(followed),
          {:ok, %Actor{} = follower} <- Actors.get_actor_by_url(follower),
-         {:ok, activity, object} <- ActivityPub.unfollow(followed, follower, id, false) do
-      Actor.unfollow(follower, followed)
+         {:ok, activity, object} <- ActivityPub.unfollow(follower, followed, id, false) do
       {:ok, activity, object}
     else
       e ->
-        Logger.error(inspect(e))
+        Logger.debug(inspect(e))
         :error
     end
   end
@@ -300,14 +366,14 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
 
     with actor <- get_actor(data),
          {:ok, %Actor{url: _actor_url}} <- Actors.get_actor_by_url(actor),
-         {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
+         {:ok, object} <- fetch_obj_helper(object_id),
          #  TODO : Validate that DELETE comes indeed form right domain (see above)
          #  :ok <- contain_origin(actor_url, object.data),
          {:ok, activity, object} <- ActivityPub.delete(object, false) do
       {:ok, activity, object}
     else
       e ->
-        Logger.error(inspect(e))
+        Logger.debug(inspect(e))
         :error
     end
   end
@@ -327,7 +393,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   #     ) do
   #   with actor <- get_actor(data),
   #        %Actor{} = actor <- Actors.get_or_fetch_by_url(actor),
-  #        {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
+  #        {:ok, object} <- fetch_obj_helper(object_id) || fetch_obj_helper(object_id),
   #        {:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do
   #     {:ok, activity}
   #   else
@@ -340,6 +406,20 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
     {:error, :not_supported}
   end
 
+  defp get_follow(follow_object) do
+    with follow_object_id when not is_nil(follow_object_id) <- Utils.get_url(follow_object),
+         {:not_found, %Follower{} = follow} <-
+           {:not_found, Actors.get_follow_by_url(follow_object_id)} do
+      {:ok, follow}
+    else
+      {:not_found, err} ->
+        {:error, "Follow URL not found"}
+
+      _ ->
+        {:error, "ActivityPub ID not found in Accept Follow object"}
+    end
+  end
+
   def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) do
     with false <- String.starts_with?(in_reply_to, "http"),
          {:ok, replied_to_object} <- fetch_obj_helper(in_reply_to) do
@@ -523,50 +603,23 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   #    |> Map.put("attachment", attachments)
   #  end
 
-  @spec fetch_obj_helper(String.t()) :: {:ok, %Event{}} | {:ok, %Comment{}} | {:error, any()}
-  def fetch_obj_helper(url) when is_bitstring(url), do: ActivityPub.fetch_object_from_url(url)
+  @spec fetch_obj_helper(map() | String.t()) :: Event.t() | Comment.t() | Actor.t() | any()
+  def fetch_obj_helper(object) do
+    Logger.debug("Fetching object #{inspect(object)}")
 
-  @spec fetch_obj_helper(map()) :: {:ok, %Event{}} | {:ok, %Comment{}} | {:error, any()}
-  def fetch_obj_helper(obj) when is_map(obj), do: ActivityPub.fetch_object_from_url(obj["id"])
+    case object |> Utils.get_url() |> ActivityPub.fetch_object_from_url() do
+      {:ok, object} ->
+        {:ok, object}
 
-  @spec get_obj_helper(String.t()) :: {:ok, struct()} | nil
-  def get_obj_helper(id) do
-    if object = normalize(id), do: {:ok, object}, else: nil
-  end
-
-  @spec normalize(map()) :: struct() | nil
-  def normalize(obj) when is_map(obj), do: get_anything_by_url(obj["id"])
-
-  @spec normalize(String.t()) :: struct() | nil
-  def normalize(url) when is_binary(url), do: get_anything_by_url(url)
-
-  @spec normalize(any()) :: nil
-  def normalize(_), do: nil
-
-  @spec normalize(String.t()) :: struct() | nil
-  def get_anything_by_url(url) do
-    Logger.debug(fn -> "Getting anything from url #{url}" end)
-    get_actor_url(url) || get_event_url(url) || get_comment_url(url)
-  end
-
-  defp get_actor_url(url) do
-    case Actors.get_actor_by_url(url) do
-      {:ok, %Actor{} = actor} -> actor
-      _ -> nil
+      err ->
+        Logger.info("Error while fetching #{inspect(object)}")
+        {:error, err}
     end
   end
 
-  defp get_event_url(url) do
-    case Events.get_event_by_url(url) do
-      {:ok, %Event{} = event} -> event
-      _ -> nil
-    end
-  end
-
-  defp get_comment_url(url) do
-    case Events.get_comment_full_from_url(url) do
-      {:ok, %Comment{} = comment} -> comment
-      _ -> nil
+  def fetch_obj_helper_as_activity_streams(object) do
+    with {:ok, object} <- fetch_obj_helper(object) do
+      {:ok, Mobilizon.Service.ActivityPub.Convertible.model_to_as(object)}
     end
   end
 end
diff --git a/lib/service/activity_pub/utils.ex b/lib/service/activity_pub/utils.ex
index 59c0b1c45..dd584992b 100644
--- a/lib/service/activity_pub/utils.ex
+++ b/lib/service/activity_pub/utils.ex
@@ -30,12 +30,9 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
 
   # Some implementations send the actor URI as the actor field, others send the entire actor object,
   # so figure out what the actor's URI is based on what we have.
-  def get_url(object) do
-    case object do
-      %{"id" => id} -> id
-      id -> id
-    end
-  end
+  def get_url(%{"id" => id}), do: id
+  def get_url(id) when is_bitstring(id), do: id
+  def get_url(_), do: nil
 
   def make_json_ld_header do
     %{
@@ -150,7 +147,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
     else
       err ->
         Logger.error("Error while inserting a remote comment inside database")
-        Logger.error(inspect(err))
+        Logger.debug(inspect(err))
         {:error, err}
     end
   end
@@ -172,7 +169,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
     else
       err ->
         Logger.error("Error while inserting a remote comment inside database")
-        Logger.error(inspect(err))
+        Logger.debug(inspect(err))
         {:error, err}
     end
   end
@@ -463,61 +460,98 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
       "object" => followed_id
     }
 
+    data =
+      if activity_id,
+        do: Map.put(data, "id", activity_id),
+        else: data
+
     Logger.debug(inspect(data))
 
-    if activity_id,
-      do: Map.put(data, "id", activity_id),
-      else: data
+    data
   end
 
   #### Announce-related helpers
 
+  require Logger
+
   @doc """
   Make announce activity data for the given actor and object
   """
+  def make_announce_data(actor, object, activity_id, public \\ true)
+
   def make_announce_data(
-        %Actor{url: actor_url} = actor,
-        %Event{url: event_url} = object,
-        activity_id
-      ) do
+        %Actor{url: actor_url, followers_url: actor_followers_url} = _actor,
+        %{"id" => url, "type" => type} = _object,
+        activity_id,
+        public
+      )
+      when type in ["Group", "Person", "Application"] do
+    do_make_announce_data(actor_url, actor_followers_url, url, url, activity_id, public)
+  end
+
+  def make_announce_data(
+        %Actor{url: actor_url, followers_url: actor_followers_url} = _actor,
+        %{"id" => url, "type" => type, "actor" => object_actor_url} = _object,
+        activity_id,
+        public
+      )
+      when type in ["Note", "Event"] do
+    do_make_announce_data(
+      actor_url,
+      actor_followers_url,
+      object_actor_url,
+      url,
+      activity_id,
+      public
+    )
+  end
+
+  defp do_make_announce_data(
+         actor_url,
+         actor_followers_url,
+         object_actor_url,
+         object_url,
+         activity_id,
+         public \\ true
+       ) do
+    {to, cc} =
+      if public do
+        {[actor_followers_url, object_actor_url],
+         ["https://www.w3.org/ns/activitystreams#Public"]}
+      else
+        {[actor_followers_url], []}
+      end
+
     data = %{
       "type" => "Announce",
       "actor" => actor_url,
-      "object" => event_url,
-      "to" => [actor.followers_url, object.actor.url],
-      "cc" => ["https://www.w3.org/ns/activitystreams#Public"]
-      # "context" => object.data["context"]
+      "object" => object_url,
+      "to" => to,
+      "cc" => cc
     }
 
     if activity_id, do: Map.put(data, "id", activity_id), else: data
   end
 
   @doc """
-  Make announce activity data for the given actor and object
+  Make unannounce activity data for the given actor and object
   """
-  def make_announce_data(
-        %Actor{url: actor_url} = actor,
-        %Comment{url: comment_url} = object,
+  def make_unannounce_data(
+        %Actor{url: url} = actor,
+        activity,
         activity_id
       ) do
     data = %{
-      "type" => "Announce",
-      "actor" => actor_url,
-      "object" => comment_url,
-      "to" => [actor.followers_url, object.actor.url],
+      "type" => "Undo",
+      "actor" => url,
+      "object" => activity,
+      "to" => [actor.followers_url, actor.url],
       "cc" => ["https://www.w3.org/ns/activitystreams#Public"]
-      # "context" => object.data["context"]
     }
 
     if activity_id, do: Map.put(data, "id", activity_id), else: data
   end
 
-  def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do
-    with announcements <- [actor | object.data["announcements"] || []] |> Enum.uniq() do
-      update_element_in_object("announcement", announcements, object)
-    end
-  end
-
   #### Unfollow-related helpers
 
   @spec make_unfollow_data(Actor.t(), Actor.t(), map(), String.t()) :: map()
@@ -553,7 +587,8 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
       "to" => params.to |> Enum.uniq(),
       "actor" => params.actor.url,
       "object" => params.object,
-      "published" => published
+      "published" => published,
+      "id" => params.object["id"] <> "/activity"
     }
     |> Map.merge(additional)
   end
diff --git a/lib/service/activity_pub/visibility.ex b/lib/service/activity_pub/visibility.ex
new file mode 100644
index 000000000..aaf114dcb
--- /dev/null
+++ b/lib/service/activity_pub/visibility.ex
@@ -0,0 +1,21 @@
+# Portions of this file are derived from Pleroma:
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social>
+# SPDX-License-Identifier: AGPL-3.0-only
+# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/visibility.ex
+
+defmodule Mobilizon.Service.ActivityPub.Visibility do
+  @moduledoc """
+  Utility functions related to content visibility
+  """
+  alias Mobilizon.Activity
+  alias Mobilizon.Events.Event
+
+  @public "https://www.w3.org/ns/activitystreams#Public"
+
+  @spec is_public?(Activity.t() | map()) :: boolean()
+  def is_public?(%{data: %{"type" => "Tombstone"}}), do: false
+  def is_public?(%{data: data}), do: is_public?(data)
+  def is_public?(%Activity{data: data}), do: is_public?(data)
+  def is_public?(data) when is_map(data), do: @public in (data["to"] ++ (data["cc"] || []))
+  def is_public?(err), do: raise(ArgumentError, message: "Invalid argument #{inspect(err)}")
+end
diff --git a/lib/service/federator.ex b/lib/service/federator.ex
index da9d54205..5e19e8a4c 100644
--- a/lib/service/federator.ex
+++ b/lib/service/federator.ex
@@ -58,10 +58,11 @@ defmodule Mobilizon.Service.Federator do
       %Activity{} ->
         Logger.info("Already had #{params["id"]}")
 
-      _e ->
+      e ->
         # Just drop those for now
         Logger.error("Unhandled activity")
-        Logger.error(Jason.encode!(params))
+        Logger.debug(inspect(e))
+        Logger.debug(Jason.encode!(params))
     end
   end
 
@@ -75,7 +76,7 @@ defmodule Mobilizon.Service.Federator do
   end
 
   def enqueue(type, payload, priority \\ 1) do
-    Logger.debug("enqueue")
+    Logger.debug("enqueue something with type #{inspect(type)}")
 
     if Mix.env() == :test do
       handle(type, payload)
@@ -111,7 +112,7 @@ defmodule Mobilizon.Service.Federator do
   end
 
   def handle_cast(m, state) do
-    Logger.error(fn ->
+    Logger.debug(fn ->
       "Unknown: #{inspect(m)}, #{inspect(state)}"
     end)
 
diff --git a/lib/service/formatter/formatter.ex b/lib/service/formatter/formatter.ex
index 93d3779e9..7d57ceddd 100644
--- a/lib/service/formatter/formatter.ex
+++ b/lib/service/formatter/formatter.ex
@@ -9,6 +9,7 @@ defmodule Mobilizon.Service.Formatter do
   """
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Actors
+  alias Mobilizon.Service.HTML
 
   @link_regex ~r"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+"ui
   @markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
@@ -87,8 +88,8 @@ defmodule Mobilizon.Service.Formatter do
     {html_escape(text, type), mentions, hashtags}
   end
 
-  def html_escape(_text, "text/html") do
-    #    HTML.filter_tags(text)
+  def html_escape(text, "text/html") do
+    HTML.filter_tags(text)
   end
 
   def html_escape(text, "text/plain") do
diff --git a/lib/service/html.ex b/lib/service/html.ex
new file mode 100644
index 000000000..2172e090e
--- /dev/null
+++ b/lib/service/html.ex
@@ -0,0 +1,73 @@
+# Portions of this file are derived from Pleroma:
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social>
+# SPDX-License-Identifier: AGPL-3.0-only
+# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/html.ex
+
+defmodule Mobilizon.Service.HTML do
+  @moduledoc """
+  Service to filter tags out of HTML content
+  """
+  alias HtmlSanitizeEx.Scrubber
+  alias Mobilizon.Service.HTML.Scrubber.Default
+
+  def filter_tags(html), do: Scrubber.scrub(html, Default)
+end
+
+defmodule Mobilizon.Service.HTML.Scrubber.Default do
+  @moduledoc "Custom strategy to filter HTML content"
+
+  require HtmlSanitizeEx.Scrubber.Meta
+  alias HtmlSanitizeEx.Scrubber.Meta
+  # credo:disable-for-previous-line
+  # No idea how to fix this one…
+
+  Meta.remove_cdata_sections_before_scrub()
+  Meta.strip_comments()
+
+  Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], ["https", "http"])
+
+  Meta.allow_tag_with_this_attribute_values("a", "class", [
+    "hashtag",
+    "u-url",
+    "mention",
+    "u-url mention",
+    "mention u-url"
+  ])
+
+  Meta.allow_tag_with_this_attribute_values("a", "rel", [
+    "tag",
+    "nofollow",
+    "noopener",
+    "noreferrer"
+  ])
+
+  Meta.allow_tag_with_these_attributes("a", ["name", "title"])
+
+  Meta.allow_tag_with_these_attributes("abbr", ["title"])
+
+  Meta.allow_tag_with_these_attributes("b", [])
+  Meta.allow_tag_with_these_attributes("blockquote", [])
+  Meta.allow_tag_with_these_attributes("br", [])
+  Meta.allow_tag_with_these_attributes("code", [])
+  Meta.allow_tag_with_these_attributes("del", [])
+  Meta.allow_tag_with_these_attributes("em", [])
+  Meta.allow_tag_with_these_attributes("i", [])
+  Meta.allow_tag_with_these_attributes("li", [])
+  Meta.allow_tag_with_these_attributes("ol", [])
+  Meta.allow_tag_with_these_attributes("p", [])
+  Meta.allow_tag_with_these_attributes("pre", [])
+  Meta.allow_tag_with_these_attributes("strong", [])
+  Meta.allow_tag_with_these_attributes("u", [])
+  Meta.allow_tag_with_these_attributes("ul", [])
+
+  Meta.allow_tag_with_this_attribute_values("span", "class", ["h-card"])
+  Meta.allow_tag_with_these_attributes("span", [])
+
+  Meta.allow_tag_with_these_attributes("h1", [])
+  Meta.allow_tag_with_these_attributes("h2", [])
+  Meta.allow_tag_with_these_attributes("h3", [])
+  Meta.allow_tag_with_these_attributes("h4", [])
+  Meta.allow_tag_with_these_attributes("h5", [])
+
+  Meta.strip_everything_not_covered()
+end
diff --git a/lib/service/http_signatures/http_signatures.ex b/lib/service/http_signatures/http_signatures.ex
deleted file mode 100644
index 04ff0a532..000000000
--- a/lib/service/http_signatures/http_signatures.ex
+++ /dev/null
@@ -1,123 +0,0 @@
-# Portions of this file are derived from Pleroma:
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social>
-# SPDX-License-Identifier: AGPL-3.0-only
-# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/http_signatures/http_signatures.ex
-
-# https://tools.ietf.org/html/draft-cavage-http-signatures-08
-defmodule Mobilizon.Service.HTTPSignatures do
-  @moduledoc """
-  # HTTP Signatures
-
-  Generates and checks HTTP Signatures
-  """
-
-  alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.ActivityPub
-  require Logger
-
-  def split_signature(sig) do
-    default = %{"headers" => "date"}
-
-    sig =
-      sig
-      |> String.trim()
-      |> String.split(",")
-      |> Enum.reduce(default, fn part, acc ->
-        [key | rest] = String.split(part, "=")
-        value = Enum.join(rest, "=")
-        Map.put(acc, key, String.trim(value, "\""))
-      end)
-
-    Map.put(sig, "headers", String.split(sig["headers"], ~r/\s/))
-  end
-
-  def validate(headers, signature, public_key) do
-    sigstring = build_signing_string(headers, signature["headers"])
-
-    Logger.debug(fn ->
-      "Signature: #{signature["signature"]}"
-    end)
-
-    Logger.debug(fn ->
-      "Sigstring: #{sigstring}"
-    end)
-
-    {:ok, sig} = Base.decode64(signature["signature"])
-    :public_key.verify(sigstring, :sha256, sig, public_key)
-  end
-
-  def validate_conn(conn) do
-    # TODO: How to get the right key and see if it is actually valid for that request.
-    # For now, fetch the key for the actor.
-    case conn.params["actor"] |> Actor.get_public_key_for_url() do
-      {:ok, public_key} ->
-        if validate_conn(conn, public_key) do
-          true
-          Logger.info("Could not validate request, re-fetching user and trying one more time")
-          # Fetch user anew and try one more time
-          with actor_id <- conn.params["actor"],
-               {:ok, _actor} <- ActivityPub.make_actor_from_url(actor_id),
-               {:ok, public_key} <- actor_id |> Actor.get_public_key_for_url() do
-            validate_conn(conn, public_key)
-          end
-        end
-
-      e ->
-        Logger.debug("Could not found url for actor!")
-        Logger.debug(inspect(e))
-        false
-    end
-  end
-
-  def validate_conn(conn, public_key) do
-    headers = Enum.into(conn.req_headers, %{})
-    host_without_port = String.split(headers["host"], ":") |> hd
-    headers = Map.put(headers, "host", host_without_port)
-    signature = split_signature(headers["signature"])
-    validate(headers, signature, public_key)
-  end
-
-  def build_signing_string(headers, used_headers) do
-    used_headers
-    |> Enum.map(fn header -> "#{header}: #{headers[header]}" end)
-    |> Enum.join("\n")
-  end
-
-  def sign(%Actor{} = actor, headers) do
-    with sigstring <- build_signing_string(headers, Map.keys(headers)),
-         {:ok, key} <- actor.keys |> Actor.prepare_public_key(),
-         signature <- sigstring |> :public_key.sign(:sha256, key) |> Base.encode64() do
-      [
-        keyId: actor.url <> "#main-key",
-        algorithm: "rsa-sha256",
-        headers: headers |> Map.keys() |> Enum.join(" "),
-        signature: signature
-      ]
-      |> Enum.map(fn {k, v} -> "#{k}=\"#{v}\"" end)
-      |> Enum.join(",")
-    else
-      err ->
-        Logger.error("Unable to sign headers")
-        Logger.error(inspect(err))
-        nil
-    end
-  end
-
-  def generate_date_header(date \\ Timex.now("GMT")) do
-    case Timex.format(date, "%a, %d %b %Y %H:%M:%S %Z", :strftime) do
-      {:ok, date} ->
-        date
-
-      {:error, err} ->
-        Logger.error("Unable to generate date header")
-        Logger.error(inspect(err))
-        nil
-    end
-  end
-
-  def generate_request_target(method, path), do: "#{method} #{path}"
-
-  def build_digest(body) do
-    "SHA-256=" <> (:crypto.hash(:sha256, body) |> Base.encode64())
-  end
-end
diff --git a/lib/service/http_signatures/signature.ex b/lib/service/http_signatures/signature.ex
new file mode 100644
index 000000000..4fc6dcfb3
--- /dev/null
+++ b/lib/service/http_signatures/signature.ex
@@ -0,0 +1,83 @@
+# Portions of this file are derived from Pleroma:
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social>
+# SPDX-License-Identifier: AGPL-3.0-only
+# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/signature.ex
+
+defmodule Mobilizon.Service.HTTPSignatures.Signature do
+  @moduledoc """
+  Adapter for the `HTTPSignatures` lib that handles signing and providing public keys to verify HTTPSignatures
+  """
+  @behaviour HTTPSignatures.Adapter
+
+  alias Mobilizon.Actors.Actor
+  alias Mobilizon.Service.ActivityPub
+  require Logger
+
+  def key_id_to_actor_url(key_id) do
+    uri =
+      URI.parse(key_id)
+      |> Map.put(:fragment, nil)
+
+    uri =
+      if not is_nil(uri.path) and String.ends_with?(uri.path, "/publickey") do
+        Map.put(uri, :path, String.replace(uri.path, "/publickey", ""))
+      else
+        uri
+      end
+
+    URI.to_string(uri)
+  end
+
+  def fetch_public_key(conn) do
+    with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
+         actor_id <- key_id_to_actor_url(kid),
+         :ok <- Logger.debug("Fetching public key for #{actor_id}"),
+         {:ok, public_key} <- Actor.get_public_key_for_url(actor_id) do
+      {:ok, public_key}
+    else
+      e ->
+        {:error, e}
+    end
+  end
+
+  def refetch_public_key(conn) do
+    with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
+         actor_id <- key_id_to_actor_url(kid),
+         :ok <- Logger.debug("Refetching public key for #{actor_id}"),
+         {:ok, _actor} <- ActivityPub.make_actor_from_url(actor_id),
+         {:ok, public_key} <- Actor.get_public_key_for_url(actor_id) do
+      {:ok, public_key}
+    else
+      e ->
+        {:error, e}
+    end
+  end
+
+  def sign(%Actor{} = actor, headers) do
+    Logger.debug("Signing on behalf of #{actor.url}")
+    Logger.debug("headers")
+    Logger.debug(inspect(headers))
+
+    with {:ok, key} <- actor.keys |> Actor.prepare_public_key() do
+      HTTPSignatures.sign(key, actor.url <> "#main-key", headers)
+    end
+  end
+
+  def generate_date_header(date \\ Timex.now("GMT")) do
+    case Timex.format(date, "%a, %d %b %Y %H:%M:%S %Z", :strftime) do
+      {:ok, date} ->
+        date
+
+      {:error, err} ->
+        Logger.error("Unable to generate date header")
+        Logger.debug(inspect(err))
+        nil
+    end
+  end
+
+  def generate_request_target(method, path), do: "#{method} #{path}"
+
+  def build_digest(body) do
+    "SHA-256=" <> (:crypto.hash(:sha256, body) |> Base.encode64())
+  end
+end
diff --git a/mix.exs b/mix.exs
index 4357ae930..83d043e07 100644
--- a/mix.exs
+++ b/mix.exs
@@ -93,6 +93,10 @@ defmodule Mobilizon.Mixfile do
       {:auto_linker,
        git: "https://git.pleroma.social/pleroma/auto_linker.git",
        ref: "95e8188490e97505c56636c1379ffdf036c1fdde"},
+      {:http_signatures,
+       git: "https://git.pleroma.social/pleroma/http_signatures.git",
+       ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"},
+      {:html_sanitize_ex, "~> 1.3.0"},
       # Dev and test dependencies
       {:phoenix_live_reload, "~> 1.2", only: :dev},
       {:ex_machina, "~> 2.3", only: [:dev, :test]},
@@ -279,7 +283,7 @@ defmodule Mobilizon.Mixfile do
         MobilizonWeb.HTTPSignaturePlug,
         MobilizonWeb.WebFingerController,
         MobilizonWeb.NodeInfoController,
-        Mobilizon.Service.HTTPSignatures,
+        Mobilizon.Service.HTTPSignatures.Signature,
         Mobilizon.Service.WebFinger,
         Mobilizon.Service.XmlBuilder,
         Mobilizon.Service.Federator
diff --git a/mix.lock b/mix.lock
index 286bbc004..7bfc696ec 100644
--- a/mix.lock
+++ b/mix.lock
@@ -56,7 +56,9 @@
   "guardian": {:hex, :guardian, "1.2.1", "bdc8dd3dbf0fb7216cb6f91c11831faa1a64d39cdaed9a611e37f2413e584983", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"},
   "guardian_db": {:hex, :guardian_db, "2.0.1", "e62e383197e957cb9c6683926d45056ab814eb0362e3de7f65d4619ae19544e8", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.1.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:guardian, "~> 1.0", [hex: :guardian, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"},
   "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
+  "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
   "http_sign": {:hex, :http_sign, "0.1.1", "b16edb83aa282892f3271f9a048c155e772bf36e15700ab93901484c55f8dd10", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
+  "http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]},
   "httpoison": {:hex, :httpoison, "1.5.1", "0f55b5b673b03c5c327dac7015a67cb571b99b631acc0bc1b0b98dcd6b9f2104", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
   "icalendar": {:git, "https://github.com/tcitworld/icalendar.git", "bd08e872c125f70a87c3ac7d87ea2f22a5577059", []},
   "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
@@ -73,6 +75,7 @@
   "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
   "mix_test_watch": {:hex, :mix_test_watch, "0.9.0", "c72132a6071261893518fa08e121e911c9358713f62794a90c95db59042af375", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm"},
   "mmdb2_decoder": {:hex, :mmdb2_decoder, "1.1.0", "2e2347521bb3bf6b81b9ee58d3be2199cb68ea42dcbafcd0d8eb40214d2844cf", [:mix], [], "hexpm"},
+  "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
   "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
   "mogrify": {:hex, :mogrify, "0.7.2", "4d00b60288e338028e2af4cccff9b0da365d83b7e5da52e58fb2de513ef5fedd", [:mix], [], "hexpm"},
   "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
diff --git a/priv/repo/migrations/20190806131306_add_url_to_follows_and_move_to_uuid.exs b/priv/repo/migrations/20190806131306_add_url_to_follows_and_move_to_uuid.exs
new file mode 100644
index 000000000..2353ef9be
--- /dev/null
+++ b/priv/repo/migrations/20190806131306_add_url_to_follows_and_move_to_uuid.exs
@@ -0,0 +1,21 @@
+defmodule Mobilizon.Repo.Migrations.AddUrlToFollowsAndMoveToUuid do
+  use Ecto.Migration
+
+  def up do
+    alter table(:followers, primary_key: false) do
+      remove(:score)
+      remove(:id)
+      add(:id, :uuid, primary_key: true)
+      add(:url, :string, null: false)
+    end
+  end
+
+  def down do
+    alter table(:followers, primary_key: true) do
+      add(:score, :integer, default: 1000)
+      remove(:id)
+      add(:id, :serial, primary_key: true)
+      remove(:url)
+    end
+  end
+end
diff --git a/schema.graphql b/schema.graphql
index e69b2c165..ef587c2d6 100644
--- a/schema.graphql
+++ b/schema.graphql
@@ -1,5 +1,5 @@
 # source: http://localhost:4000/api
-# timestamp: Mon Jul 29 2019 15:24:10 GMT+0200 (GMT+02:00)
+# timestamp: Wed Aug 07 2019 17:57:34 GMT+0200 (GMT+02:00)
 
 schema {
   query: RootQueryType
@@ -119,6 +119,7 @@ type Address {
 
   """The address's street name (with number)"""
   street: String
+  url: String
 }
 
 input AddressInput {
@@ -138,6 +139,7 @@ input AddressInput {
 
   """The address's street name (with number)"""
   street: String
+  url: String
 }
 
 """A comment"""
@@ -688,7 +690,7 @@ type RootMutationType {
   """Create an event"""
   createEvent(
     beginsOn: DateTime!
-    category: String!
+    category: String
     description: String!
     endsOn: DateTime
     onlineAddress: String
diff --git a/test/fixtures/mastodon-accept-activity.json b/test/fixtures/mastodon-accept-activity.json
new file mode 100644
index 000000000..222b04e9f
--- /dev/null
+++ b/test/fixtures/mastodon-accept-activity.json
@@ -0,0 +1,34 @@
+{
+  "type": "Accept",
+  "signature": {
+    "type": "RsaSignature2017",
+    "signatureValue": "rBzK4Kqhd4g7HDS8WE5oRbWQb2R+HF/6awbUuMWhgru/xCODT0SJWSri0qWqEO4fPcpoUyz2d25cw6o+iy9wiozQb3hQNnu69AR+H5Mytc06+g10KCHexbGhbAEAw/7IzmeXELHUbaqeduaDIbdt1zw4RkwLXdqgQcGXTJ6ND1wM3WMHXQCK1m0flasIXFoBxpliPAGiElV8s0+Ltuh562GvflG3kB3WO+j+NaR0ZfG5G9N88xMj9UQlCKit5gpAE5p6syUsCU2WGBHywTumv73i3OVTIFfq+P9AdMsRuzw1r7zoKEsthW4aOzLQDi01ZjvdBz8zH6JnjDU7SMN/Ig==",
+    "creator": "http://mastodon.example.org/users/admin#main-key",
+    "created": "2018-02-17T14:36:41Z"
+  },
+  "object": {
+    "type": "Follow",
+    "object": "http://mobilizon.test/@thomas0",
+    "actor": "http://mobilizon.test/@thomas1",
+    "id": "http://mobilizon.test/follows/fdfds"
+  },
+  "nickname": "lain",
+  "id": "\"id\": \"http://mobilizon.test/accepts/follows/fdfds",
+  "actor": "http://mobilizon.test/@thomas0",
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    "https://w3id.org/security/v1",
+    {
+      "toot": "http://joinmastodon.org/ns#",
+      "sensitive": "as:sensitive",
+      "ostatus": "http://ostatus.org#",
+      "movedTo": "as:movedTo",
+      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+      "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+      "conversation": "ostatus:conversation",
+      "atomUri": "ostatus:atomUri",
+      "Hashtag": "as:Hashtag",
+      "Emoji": "toot:Emoji"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/test/fixtures/mastodon-announce.json b/test/fixtures/mastodon-announce.json
index 26fb1a09a..83da31bbc 100644
--- a/test/fixtures/mastodon-announce.json
+++ b/test/fixtures/mastodon-announce.json
@@ -10,14 +10,14 @@
     "created": "2018-02-17T19:39:15Z"
   },
   "published": "2018-02-17T19:39:15Z",
-  "object": "https://social.tcit.fr/@tcit/101188891162897047",
-  "id": "https://social.tcit.fr/users/tcit/statuses/101188891162897047/activity",
+  "object": "https://framapiaf.org/users/Framasoft/statuses/102501959686438400",
+  "id": "https://framapiaf.org/users/Framasoft/statuses/102501959686438400/activity",
   "cc": [
-    "https://social.tcit.fr/users/tcit",
-    "https://social.tcit.fr/users/tcit/followers"
+    "https://framapiaf.org/users/Framasoft",
+    "https://framapiaf.org/users/Framasoft/followers"
   ],
-  "atomUri": "https://social.tcit.fr/users/tcit/statuses/101188891162897047/activity",
-  "actor": "https://social.tcit.fr/users/tcit",
+  "atomUri": "https://framapiaf.org/users/Framasoft/statuses/102501959686438400/activity",
+  "actor": "https://framapiaf.org/users/Framasoft",
   "@context": [
     "https://www.w3.org/ns/activitystreams",
     "https://w3id.org/security/v1",
diff --git a/test/fixtures/mastodon-reject-activity.json b/test/fixtures/mastodon-reject-activity.json
new file mode 100644
index 000000000..9559d6c73
--- /dev/null
+++ b/test/fixtures/mastodon-reject-activity.json
@@ -0,0 +1,34 @@
+{
+  "type": "Reject",
+  "signature": {
+    "type": "RsaSignature2017",
+    "signatureValue": "rBzK4Kqhd4g7HDS8WE5oRbWQb2R+HF/6awbUuMWhgru/xCODT0SJWSri0qWqEO4fPcpoUyz2d25cw6o+iy9wiozQb3hQNnu69AR+H5Mytc06+g10KCHexbGhbAEAw/7IzmeXELHUbaqeduaDIbdt1zw4RkwLXdqgQcGXTJ6ND1wM3WMHXQCK1m0flasIXFoBxpliPAGiElV8s0+Ltuh562GvflG3kB3WO+j+NaR0ZfG5G9N88xMj9UQlCKit5gpAE5p6syUsCU2WGBHywTumv73i3OVTIFfq+P9AdMsRuzw1r7zoKEsthW4aOzLQDi01ZjvdBz8zH6JnjDU7SMN/Ig==",
+    "creator": "http://mastodon.example.org/users/admin#main-key",
+    "created": "2018-02-17T14:36:41Z"
+  },
+  "object": {
+    "type": "Follow",
+    "object": "http://mastodon.example.org/users/admin",
+    "id": "http://localtesting.pleroma.lol/users/lain#follows/4",
+    "actor": "http://localtesting.pleroma.lol/users/lain"
+  },
+  "nickname": "lain",
+  "id": "http://mastodon.example.org/users/admin#rejects/follows/4",
+  "actor": "http://mastodon.example.org/users/admin",
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    "https://w3id.org/security/v1",
+    {
+      "toot": "http://joinmastodon.org/ns#",
+      "sensitive": "as:sensitive",
+      "ostatus": "http://ostatus.org#",
+      "movedTo": "as:movedTo",
+      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+      "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+      "conversation": "ostatus:conversation",
+      "atomUri": "ostatus:atomUri",
+      "Hashtag": "as:Hashtag",
+      "Emoji": "toot:Emoji"
+    }
+  ]
+}
diff --git a/test/fixtures/mastodon-undo-announce.json b/test/fixtures/mastodon-undo-announce.json
index 05332bed2..b239f7485 100644
--- a/test/fixtures/mastodon-undo-announce.json
+++ b/test/fixtures/mastodon-undo-announce.json
@@ -12,17 +12,17 @@
        "http://www.w3.org/ns/activitystreams#Public"
      ],
      "published": "2018-05-11T16:23:37Z",
-     "object": "http://mastodon.example.org/@admin/99541947525187367",
-     "id": "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity",
+     "object": "https://framapiaf.org/@Framasoft/statuses/102501959686438400",
+     "id": "https://framapiaf.org/users/Framasoft/statuses/102501959686438400/activity",
      "cc": [
-       "http://mastodon.example.org/users/admin",
-       "http://mastodon.example.org/users/admin/followers"
+       "https://framapiaf.org/users/Framasoft/",
+       "https://framapiaf.org/users/Framasoft/followers"
      ],
-     "atomUri": "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity",
-     "actor": "http://mastodon.example.org/users/admin"
+     "atomUri": "https://framapiaf.org/users/Framasoft/statuses/102501959686438400/activity",
+     "actor": "https://framapiaf.org/users/Framasoft"
    },
-   "id": "http://mastodon.example.org/users/admin#announces/100011594053806179/undo",
-   "actor": "http://mastodon.example.org/users/admin",
+   "id": "https://framapiaf.org/users/Framasoft#announces/100011594053806179/undo",
+   "actor": "https://framapiaf.org/users/Framasoft",
    "@context": [
      "http://www.w3.org/ns/activitystreams",
      "http://w3id.org/security/v1",
diff --git a/test/fixtures/vcr_cassettes/relay/fetch_relay_follow.json b/test/fixtures/vcr_cassettes/relay/fetch_relay_follow.json
new file mode 100644
index 000000000..4f911b258
--- /dev/null
+++ b/test/fixtures/vcr_cassettes/relay/fetch_relay_follow.json
@@ -0,0 +1,57 @@
+[
+  {
+    "request": {
+      "body": "",
+      "headers": {
+        "Accept": "application/activity+json"
+      },
+      "method": "get",
+      "options": {
+        "follow_redirect": "true"
+      },
+      "request_body": "",
+      "url": "http://localhost:8080/actor"
+    },
+    "response": {
+      "binary": false,
+      "body": "{\"@context\": \"https://www.w3.org/ns/activitystreams\", \"endpoints\": {\"sharedInbox\": \"http://localhost:8080/inbox\"}, \"followers\": \"http://localhost:8080/followers\", \"following\": \"http://localhost:8080/following\", \"inbox\": \"http://localhost:8080/inbox\", \"name\": \"ActivityRelay\", \"type\": \"Application\", \"id\": \"http://localhost:8080/actor\", \"publicKey\": {\"id\": \"http://localhost:8080/actor#main-key\", \"owner\": \"http://localhost:8080/actor\", \"publicKeyPem\": \"-----BEGIN PUBLIC KEY-----\\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvs6UuAo26Sb3BiOK7xay\\nsBzqvXI3xd55JAP0pAk2faF+Vl3r67/g9MoND96JqCVMuzSJZ9oSsqa6ilJCxG3p\\nXUUfQUvqAMGW49cCvga86DG17Ennjbc4C6WIQtoW3Wm5OdDciPY2Dx+pSXdTOajB\\nFX6RHUZcgqHENrsm3jPZI138e/2OJeqdxv4/5t2xdPXEpWdPGitX9AJhrqPY4lzg\\nzQ9Y9wS2eS1CVL9vZZRf9Z4RiZvAfVb0s1iS/IUxrf4TYERRFJxEoDLD2SZVrkq6\\nvhGldCfw2ZnfTftA1ToXguC9S6nSaz+li0ajNjpK/xjZjlKvn0I078UPPe5LUlsb\\nUcYZvBx5PC5rV8yKMLlgxnTY8PqC8LEVc453wO7Ai4M5TeB0SUyEycZHSyLfvQXV\\nThEN/07u1UaJViY3U5S/SihyoCQUfJXQ3jx2SjGgM32/aJ3IwxgveLaTsaZ0VVKM\\nbawEFw6iAcWYM06hZSB6j6dkL1xh+FYGEQTPMYMqUOJi2r1cD8yMLe8dTFOmwMLt\\nBnf7xxvnjKJcv3e9zGRWIdLkQbBQn3BEuRTCUMgljipxdjbeE5/JSP1kQLB94ncb\\nb9gvYgtemJKvT8m37+HOi9MI4BMIlDwpRWjqPZmkNvkegR/1KPjJSsyAnGdd89ne\\np442vUqPyXIq0tSCDmjmU+cCAwEAAQ==\\n-----END PUBLIC KEY-----\"}, \"summary\": \"ActivityRelay bot\", \"preferredUsername\": \"relay\", \"url\": \"http://localhost:8080/actor\"}",
+      "headers": {
+        "Content-Type": "application/json; charset=utf-8",
+        "Content-Length": "1368",
+        "Date": "Thu, 01 Aug 2019 14:44:38 GMT",
+        "Server": "Python/3.7 aiohttp/3.3.2"
+      },
+      "status_code": 200,
+      "type": "ok"
+    }
+  },
+  {
+    "request": {
+      "body": "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://litepub.github.io/litepub/context.jsonld\",{\"Hashtag\":\"as:Hashtag\",\"category\":\"sc:category\",\"sc\":\"http://schema.org#\",\"uuid\":\"sc:identifier\"}],\"actor\":\"http://mobilizon.test/relay\",\"cc\":[\"https://www.w3.org/ns/activitystreams#Public\"],\"id\":\"http://mobilizon.test/follow/69/activity\",\"object\":\"http://localhost:8080/actor\",\"to\":[\"http://localhost:8080/actor\"],\"type\":\"Follow\"}",
+      "headers": {
+        "Content-Type": "application/activity+json",
+        "signature": "keyId=\"http://mobilizon.test/relay#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) content-length date digest host\",signature=\"UADlb5eaeqmujO5zGfK1mWB3WZFXU6lkUgSvEf5YyQMOIkMaudDwTfNPIa4IYh2VMLwyYSjOOXxkcBdCw4f9UnMBQBhomPNRNkJ0QBzoxILPmyxddAojH9IzwwAUL/nHSGWaO116bkCux0OcEM5AVIrCT6dENep39lOjnOGPelBB5mKMS78AxH4pU/5tTGFKmNgiRL4Q06ezPUJHKauRrMwzcqZYdjUn+U9MDBDrYyfAzqQlgBPU/fMCjwusndxaICb9c+40YE3WaXzKewIivfrMoOBzWyw6ZsgAG8/NoOH+8z9Z+hBvdjCUXeG2bvAPPclNkSJillwIA2PnMOVgpw==\"",
+        "digest": "SHA-256=Ady0Dj2bEXe201P9bThLaj1Kw/7O1cfrjN9IifEfVBg=",
+        "date": "Thu, 01 Aug 2019 14:44:38 GMT"
+      },
+      "method": "post",
+      "options": {
+        "pool": "default"
+      },
+      "request_body": "",
+      "url": "http://localhost:8080/inbox"
+    },
+    "response": {
+      "binary": false,
+      "body": "signature check failed, signature did not match key",
+      "headers": {
+        "Content-Length": "51",
+        "Content-Type": "text/plain; charset=utf-8",
+        "Date": "Thu, 01 Aug 2019 14:44:38 GMT",
+        "Server": "Python/3.7 aiohttp/3.3.2"
+      },
+      "status_code": 401,
+      "type": "ok"
+    }
+  }
+]
\ No newline at end of file
diff --git a/test/fixtures/vcr_cassettes/relay/fetch_relay_unfollow.json b/test/fixtures/vcr_cassettes/relay/fetch_relay_unfollow.json
new file mode 100644
index 000000000..0c2abfe16
--- /dev/null
+++ b/test/fixtures/vcr_cassettes/relay/fetch_relay_unfollow.json
@@ -0,0 +1,57 @@
+[
+  {
+    "request": {
+      "body": "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://litepub.github.io/litepub/context.jsonld\",{\"Hashtag\":\"as:Hashtag\",\"category\":\"sc:category\",\"sc\":\"http://schema.org#\",\"uuid\":\"sc:identifier\"}],\"actor\":\"http://mobilizon.test/relay\",\"cc\":[\"https://www.w3.org/ns/activitystreams#Public\"],\"id\":\"http://mobilizon.test/follow/68/activity\",\"object\":\"http://localhost:8080/actor\",\"to\":[\"http://localhost:8080/actor\"],\"type\":\"Follow\"}",
+      "headers": {
+        "Content-Type": "application/activity+json",
+        "signature": "keyId=\"http://mobilizon.test/relay#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) content-length date digest host\",signature=\"WsxzipdObXsApVtY5l2yTonTOPV888XLKK2+AMQRyiNZm4RGMEux8kgBKgJIODaKmRx9EsX8dIzBtTmJdLyj5gqfjvGVyj8hVeR0ERNMZmjngh5EZ3W+ySbkdFYZeYDWhwpL1i+7dTFJ3zE/ASZVaTMeIgqEpFnzHNbamwPzBZVvcnzyraB1rrmwcbzzrk3UPlJ3tA+Xz67Njr2wOiNNsjZ53abArKZB3KGbife6OyrVrKldJ+UKZS+vokgUXFwvMBZxfdmH2GD+yXHPhCIu7bVu77ASdW7bl7tM3uIV/c/Wemy5qJtPOupwbDvpLZ9ETE5IRCoUPdQ7l75kvevNxQ==\"",
+        "digest": "SHA-256=qIEgTH6kBorFchTiX2kxd7onyZ7BHhvLgCODLs6RAVc=",
+        "date": "Thu, 01 Aug 2019 14:44:37 GMT"
+      },
+      "method": "post",
+      "options": {
+        "pool": "default"
+      },
+      "request_body": "",
+      "url": "http://localhost:8080/inbox"
+    },
+    "response": {
+      "binary": false,
+      "body": "signature check failed, signature did not match key",
+      "headers": {
+        "Content-Length": "51",
+        "Content-Type": "text/plain; charset=utf-8",
+        "Date": "Thu, 01 Aug 2019 14:44:37 GMT",
+        "Server": "Python/3.7 aiohttp/3.3.2"
+      },
+      "status_code": 401,
+      "type": "ok"
+    }
+  },
+  {
+    "request": {
+      "body": "",
+      "headers": {
+        "Accept": "application/activity+json"
+      },
+      "method": "get",
+      "options": {
+        "follow_redirect": "true"
+      },
+      "request_body": "",
+      "url": "http://localhost:8080/actor"
+    },
+    "response": {
+      "binary": false,
+      "body": "{\"@context\": \"https://www.w3.org/ns/activitystreams\", \"endpoints\": {\"sharedInbox\": \"http://localhost:8080/inbox\"}, \"followers\": \"http://localhost:8080/followers\", \"following\": \"http://localhost:8080/following\", \"inbox\": \"http://localhost:8080/inbox\", \"name\": \"ActivityRelay\", \"type\": \"Application\", \"id\": \"http://localhost:8080/actor\", \"publicKey\": {\"id\": \"http://localhost:8080/actor#main-key\", \"owner\": \"http://localhost:8080/actor\", \"publicKeyPem\": \"-----BEGIN PUBLIC KEY-----\\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvs6UuAo26Sb3BiOK7xay\\nsBzqvXI3xd55JAP0pAk2faF+Vl3r67/g9MoND96JqCVMuzSJZ9oSsqa6ilJCxG3p\\nXUUfQUvqAMGW49cCvga86DG17Ennjbc4C6WIQtoW3Wm5OdDciPY2Dx+pSXdTOajB\\nFX6RHUZcgqHENrsm3jPZI138e/2OJeqdxv4/5t2xdPXEpWdPGitX9AJhrqPY4lzg\\nzQ9Y9wS2eS1CVL9vZZRf9Z4RiZvAfVb0s1iS/IUxrf4TYERRFJxEoDLD2SZVrkq6\\nvhGldCfw2ZnfTftA1ToXguC9S6nSaz+li0ajNjpK/xjZjlKvn0I078UPPe5LUlsb\\nUcYZvBx5PC5rV8yKMLlgxnTY8PqC8LEVc453wO7Ai4M5TeB0SUyEycZHSyLfvQXV\\nThEN/07u1UaJViY3U5S/SihyoCQUfJXQ3jx2SjGgM32/aJ3IwxgveLaTsaZ0VVKM\\nbawEFw6iAcWYM06hZSB6j6dkL1xh+FYGEQTPMYMqUOJi2r1cD8yMLe8dTFOmwMLt\\nBnf7xxvnjKJcv3e9zGRWIdLkQbBQn3BEuRTCUMgljipxdjbeE5/JSP1kQLB94ncb\\nb9gvYgtemJKvT8m37+HOi9MI4BMIlDwpRWjqPZmkNvkegR/1KPjJSsyAnGdd89ne\\np442vUqPyXIq0tSCDmjmU+cCAwEAAQ==\\n-----END PUBLIC KEY-----\"}, \"summary\": \"ActivityRelay bot\", \"preferredUsername\": \"relay\", \"url\": \"http://localhost:8080/actor\"}",
+      "headers": {
+        "Content-Type": "application/json; charset=utf-8",
+        "Content-Length": "1368",
+        "Date": "Thu, 01 Aug 2019 14:44:36 GMT",
+        "Server": "Python/3.7 aiohttp/3.3.2"
+      },
+      "status_code": 200,
+      "type": "ok"
+    }
+  }
+]
\ No newline at end of file
diff --git a/test/mobilizon/actors/actors_test.exs b/test/mobilizon/actors/actors_test.exs
index c07c917c1..bcb320724 100644
--- a/test/mobilizon/actors/actors_test.exs
+++ b/test/mobilizon/actors/actors_test.exs
@@ -479,9 +479,9 @@ defmodule Mobilizon.ActorsTest do
     alias Mobilizon.Actors.Follower
     alias Mobilizon.Actors.Actor
 
-    @valid_attrs %{approved: true, score: 42}
-    @update_attrs %{approved: false, score: 43}
-    @invalid_attrs %{approved: nil, score: nil}
+    @valid_attrs %{approved: true}
+    @update_attrs %{approved: false}
+    @invalid_attrs %{approved: nil}
 
     setup do
       actor = insert(:actor)
@@ -509,7 +509,6 @@ defmodule Mobilizon.ActorsTest do
 
       assert {:ok, %Follower{} = follower} = Actors.create_follower(valid_attrs)
       assert follower.approved == true
-      assert follower.score == 42
 
       assert %{total: 1, elements: [target_actor]} = Actor.get_followings(actor)
       assert %{total: 1, elements: [actor]} = Actor.get_followers(target_actor)
@@ -546,7 +545,6 @@ defmodule Mobilizon.ActorsTest do
       assert {:ok, follower} = Actors.update_follower(follower, @update_attrs)
       assert %Follower{} = follower
       assert follower.approved == false
-      assert follower.score == 43
     end
 
     test "update_follower/2 with invalid data returns error changeset", context do
@@ -582,12 +580,12 @@ defmodule Mobilizon.ActorsTest do
       assert actor.followings |> Enum.map(& &1.target_actor_id) == [target_actor.id]
 
       # Test if actor is already following target actor
-      {:error, msg} = Actor.follow(target_actor, actor)
+      assert {:error, :already_following, msg} = Actor.follow(target_actor, actor)
       assert msg =~ "already following"
 
       # Test if target actor is suspended
       target_actor = %{target_actor | suspended: true}
-      {:error, msg} = Actor.follow(target_actor, actor)
+      assert {:error, :suspended, msg} = Actor.follow(target_actor, actor)
       assert msg =~ "suspended"
     end
   end
diff --git a/test/mobilizon/service/activity_pub/activity_pub_test.exs b/test/mobilizon/service/activity_pub/activity_pub_test.exs
index 12aa5f373..638ed0a18 100644
--- a/test/mobilizon/service/activity_pub/activity_pub_test.exs
+++ b/test/mobilizon/service/activity_pub/activity_pub_test.exs
@@ -11,7 +11,7 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
   alias Mobilizon.Events
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Actors
-  alias Mobilizon.Service.HTTPSignatures
+  alias Mobilizon.Service.HTTPSignatures.Signature
   alias Mobilizon.Service.ActivityPub
   use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
 
@@ -24,12 +24,12 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
       actor = insert(:actor)
 
       signature =
-        HTTPSignatures.sign(actor, %{
+        Signature.sign(actor, %{
           host: "example.com",
           "content-length": 15,
-          digest: Jason.encode!(%{id: "my_id"}) |> HTTPSignatures.build_digest(),
-          "(request-target)": HTTPSignatures.generate_request_target("POST", "/inbox"),
-          date: HTTPSignatures.generate_date_header()
+          digest: Jason.encode!(%{id: "my_id"}) |> Signature.build_digest(),
+          "(request-target)": Signature.generate_request_target("POST", "/inbox"),
+          date: Signature.generate_date_header()
         })
 
       assert signature =~ "headers=\"(request-target) content-length date digest host\""
@@ -53,21 +53,21 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
   end
 
   describe "create activities" do
-    test "removes doubled 'to' recipients" do
-      actor = insert(:actor)
-
-      {:ok, activity, _} =
-        ActivityPub.create(%{
-          to: ["user1", "user1", "user2"],
-          actor: actor,
-          context: "",
-          object: %{}
-        })
-
-      assert activity.data["to"] == ["user1", "user2"]
-      assert activity.actor == actor.url
-      assert activity.recipients == ["user1", "user2"]
-    end
+    #    test "removes doubled 'to' recipients" do
+    #      actor = insert(:actor)
+    #
+    #      {:ok, activity, _} =
+    #        ActivityPub.create(%{
+    #          to: ["user1", "user1", "user2"],
+    #          actor: actor,
+    #          context: "",
+    #          object: %{}
+    #        })
+    #
+    #      assert activity.data["to"] == ["user1", "user2"]
+    #      assert activity.actor == actor.url
+    #      assert activity.recipients == ["user1", "user2"]
+    #    end
   end
 
   describe "fetching an" do
@@ -110,6 +110,7 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
   end
 
   describe "deletion" do
+    # TODO: The delete activity it relayed and fetched once again (and then not found /o\)
     test "it creates a delete activity and deletes the original event" do
       event = insert(:event)
       event = Events.get_event_full_by_url!(event.url)
diff --git a/test/mobilizon/service/activity_pub/relay_test.exs b/test/mobilizon/service/activity_pub/relay_test.exs
new file mode 100644
index 000000000..18d72405a
--- /dev/null
+++ b/test/mobilizon/service/activity_pub/relay_test.exs
@@ -0,0 +1,15 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Mobilizon.Service.ActivityPub.RelayTest do
+  use Mobilizon.DataCase
+
+  alias Mobilizon.Service.ActivityPub.Relay
+
+  test "gets an actor for the relay" do
+    actor = Relay.get_actor()
+
+    assert actor.url =~ "/relay"
+  end
+end
diff --git a/test/mobilizon/service/activity_pub/transmogrifier_test.exs b/test/mobilizon/service/activity_pub/transmogrifier_test.exs
index 56e3e296f..4cbf4b1b5 100644
--- a/test/mobilizon/service/activity_pub/transmogrifier_test.exs
+++ b/test/mobilizon/service/activity_pub/transmogrifier_test.exs
@@ -13,6 +13,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
   alias Mobilizon.Events.{Comment, Event}
+  alias Mobilizon.Service.ActivityPub
   alias Mobilizon.Service.ActivityPub.Utils
   alias Mobilizon.Service.ActivityPub.Transmogrifier
   use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
@@ -151,7 +152,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
       data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Jason.decode!()
 
       {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
-      assert Enum.at(data["object"]["tag"], 2) == "moo"
+      assert Enum.at(data["object"]["tag"], 1)["name"] == "#moo"
     end
 
     #     test "it works for incoming notices with contentMap" do
@@ -293,43 +294,41 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
     #   assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
     # end
 
-    # test "it works for incoming announces" do
-    #   data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()
+    test "it works for incoming announces" do
+      data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()
 
-    #   {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+      {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
 
-    #   assert data["actor"] == "https://social.tcit.fr/users/tcit"
-    #   assert data["type"] == "Announce"
+      assert data["actor"] == "https://framapiaf.org/users/Framasoft"
+      assert data["type"] == "Announce"
 
-    #   assert data["id"] ==
-    #            "https://social.tcit.fr/users/tcit/statuses/101188891162897047/activity"
+      assert data["id"] ==
+               "https://framapiaf.org/users/Framasoft/statuses/102501959686438400/activity"
 
-    #   assert data["object"] ==
-    #            "https://social.tcit.fr/users/tcit/statuses/101188891162897047"
+      assert data["object"] ==
+               "https://framapiaf.org/users/Framasoft/statuses/102501959686438400"
 
-    #   assert %Comment{} = Events.get_comment_from_url(data["object"])
-    # end
+      assert %Comment{} = Events.get_comment_from_url(data["object"])
+    end
 
-    # test "it works for incoming announces with an existing activity" do
-    #   comment = insert(:comment)
+    test "it works for incoming announces with an existing activity" do
+      comment = insert(:comment)
 
-    #   data =
-    #     File.read!("test/fixtures/mastodon-announce.json")
-    #     |> Jason.decode!()
-    #     |> Map.put("object", comment.url)
+      data =
+        File.read!("test/fixtures/mastodon-announce.json")
+        |> Jason.decode!()
+        |> Map.put("object", comment.url)
 
-    #   {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+      {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
 
-    #   assert data["actor"] == "https://social.tcit.fr/users/tcit"
-    #   assert data["type"] == "Announce"
+      assert data["actor"] == "https://framapiaf.org/users/Framasoft"
+      assert data["type"] == "Announce"
 
-    #   assert data["id"] ==
-    #            "https://social.tcit.fr/users/tcit/statuses/101188891162897047/activity"
+      assert data["id"] ==
+               "https://framapiaf.org/users/Framasoft/statuses/102501959686438400/activity"
 
-    #   assert data["object"] == comment.url
-
-    #   # assert Activity.get_create_activity_by_object_ap_id(data["object"]).id == activity.id
-    # end
+      assert data["object"] == comment.url
+    end
 
     test "it works for incoming update activities" do
       data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
@@ -423,32 +422,32 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
     #       assert Repo.get(Activity, activity.id)
     #     end
 
-    # test "it works for incoming unannounces with an existing notice" do
-    #   comment = insert(:comment)
+    test "it works for incoming unannounces with an existing notice" do
+      comment = insert(:comment)
 
-    #   announce_data =
-    #     File.read!("test/fixtures/mastodon-announce.json")
-    #     |> Jason.decode!()
-    #     |> Map.put("object", comment.url)
+      announce_data =
+        File.read!("test/fixtures/mastodon-announce.json")
+        |> Jason.decode!()
+        |> Map.put("object", comment.url)
 
-    #   {:ok, %Activity{data: announce_data, local: false}} =
-    #     Transmogrifier.handle_incoming(announce_data)
+      {:ok, %Activity{data: announce_data, local: false}, _} =
+        Transmogrifier.handle_incoming(announce_data)
 
-    #   data =
-    #     File.read!("test/fixtures/mastodon-undo-announce.json")
-    #     |> Jason.decode!()
-    #     |> Map.put("object", announce_data)
-    #     |> Map.put("actor", announce_data["actor"])
+      data =
+        File.read!("test/fixtures/mastodon-undo-announce.json")
+        |> Jason.decode!()
+        |> Map.put("object", announce_data)
+        |> Map.put("actor", announce_data["actor"])
 
-    #   {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+      {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
 
-    #   assert data["type"] == "Undo"
-    #   assert data["object"]["type"] == "Announce"
-    #   assert data["object"]["object"] == comment.url
+      assert data["type"] == "Undo"
+      assert data["object"]["type"] == "Announce"
+      assert data["object"]["object"] == comment.url
 
-    #   assert data["object"]["id"] ==
-    #            "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
-    # end
+      assert data["object"]["id"] ==
+               "https://framapiaf.org/users/Framasoft/statuses/102501959686438400/activity"
+    end
 
     test "it works for incomming unfollows with an existing follow" do
       actor = insert(:actor)
@@ -552,175 +551,127 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
     #       refute User.blocks?(blocker, user)
     #     end
 
-    #     test "it works for incoming accepts which were pre-accepted" do
-    #       follower = insert(:user)
-    #       followed = insert(:user)
+    test "it works for incoming accepts which were pre-accepted" do
+      follower = insert(:actor)
+      followed = insert(:actor)
 
-    #       {:ok, follower} = User.follow(follower, followed)
-    #       assert User.following?(follower, followed) == true
+      refute Actor.following?(follower, followed)
 
-    #       {:ok, follow_activity} = ActivityPub.follow(follower, followed)
+      {:ok, follow_activity, _} = ActivityPub.follow(follower, followed)
+      assert Actor.following?(follower, followed)
 
-    #       accept_data =
-    #         File.read!("test/fixtures/mastodon-accept-activity.json")
-    #         |> Jason.decode!()
-    #         |> Map.put("actor", followed.ap_id)
+      accept_data =
+        File.read!("test/fixtures/mastodon-accept-activity.json")
+        |> Jason.decode!()
+        |> Map.put("actor", followed.url)
 
-    #       object =
-    #         accept_data["object"]
-    #         |> Map.put("actor", follower.ap_id)
-    #         |> Map.put("id", follow_activity.data["id"])
+      object =
+        accept_data["object"]
+        |> Map.put("actor", follower.url)
+        |> Map.put("id", follow_activity.data["id"])
 
-    #       accept_data = Map.put(accept_data, "object", object)
+      accept_data = Map.put(accept_data, "object", object)
 
-    #       {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
-    #       refute activity.local
+      {:ok, activity, _} = Transmogrifier.handle_incoming(accept_data)
+      refute activity.local
 
-    #       assert activity.data["object"] == follow_activity.data["id"]
+      assert activity.data["object"]["id"] == follow_activity.data["id"]
 
-    #       follower = Repo.get(User, follower.id)
+      {:ok, follower} = Actors.get_actor_by_url(follower.url)
 
-    #       assert User.following?(follower, followed) == true
-    #     end
+      assert Actor.following?(follower, followed)
+    end
 
-    #     test "it works for incoming accepts which were orphaned" do
-    #       follower = insert(:user)
-    #       followed = insert(:user, %{info: %{"locked" => true}})
+    test "it works for incoming accepts which are referenced by IRI only" do
+      follower = insert(:actor)
+      followed = insert(:actor)
 
-    #       {:ok, follow_activity} = ActivityPub.follow(follower, followed)
+      {:ok, follow_activity, _} = ActivityPub.follow(follower, followed)
 
-    #       accept_data =
-    #         File.read!("test/fixtures/mastodon-accept-activity.json")
-    #         |> Jason.decode!()
-    #         |> Map.put("actor", followed.ap_id)
+      accept_data =
+        File.read!("test/fixtures/mastodon-accept-activity.json")
+        |> Jason.decode!()
+        |> Map.put("actor", followed.url)
+        |> Map.put("object", follow_activity.data["id"])
 
-    #       accept_data =
-    #         Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
+      {:ok, activity, _} = Transmogrifier.handle_incoming(accept_data)
+      assert activity.data["object"] == follow_activity.data["id"]
+      assert activity.data["object"] =~ "/follow/"
+      assert activity.data["id"] =~ "/accept/follow/"
 
-    #       {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
-    #       assert activity.data["object"] == follow_activity.data["id"]
+      {:ok, follower} = Actors.get_actor_by_url(follower.url)
 
-    #       follower = Repo.get(User, follower.id)
+      assert Actor.following?(follower, followed)
+    end
 
-    #       assert User.following?(follower, followed) == true
-    #     end
+    test "it fails for incoming accepts which cannot be correlated" do
+      follower = insert(:actor)
+      followed = insert(:actor)
 
-    #     test "it works for incoming accepts which are referenced by IRI only" do
-    #       follower = insert(:user)
-    #       followed = insert(:user, %{info: %{"locked" => true}})
+      accept_data =
+        File.read!("test/fixtures/mastodon-accept-activity.json")
+        |> Jason.decode!()
+        |> Map.put("actor", followed.url)
 
-    #       {:ok, follow_activity} = ActivityPub.follow(follower, followed)
+      accept_data =
+        Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.url))
 
-    #       accept_data =
-    #         File.read!("test/fixtures/mastodon-accept-activity.json")
-    #         |> Jason.decode!()
-    #         |> Map.put("actor", followed.ap_id)
-    #         |> Map.put("object", follow_activity.data["id"])
+      :error = Transmogrifier.handle_incoming(accept_data)
 
-    #       {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
-    #       assert activity.data["object"] == follow_activity.data["id"]
+      {:ok, follower} = Actors.get_actor_by_url(follower.url)
 
-    #       follower = Repo.get(User, follower.id)
+      refute Actor.following?(follower, followed)
+    end
 
-    #       assert User.following?(follower, followed) == true
-    #     end
+    test "it fails for incoming rejects which cannot be correlated" do
+      follower = insert(:actor)
+      followed = insert(:actor)
 
-    #     test "it fails for incoming accepts which cannot be correlated" do
-    #       follower = insert(:user)
-    #       followed = insert(:user, %{info: %{"locked" => true}})
+      accept_data =
+        File.read!("test/fixtures/mastodon-reject-activity.json")
+        |> Jason.decode!()
+        |> Map.put("actor", followed.url)
 
-    #       accept_data =
-    #         File.read!("test/fixtures/mastodon-accept-activity.json")
-    #         |> Jason.decode!()
-    #         |> Map.put("actor", followed.ap_id)
+      accept_data =
+        Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.url))
 
-    #       accept_data =
-    #         Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
+      :error = Transmogrifier.handle_incoming(accept_data)
 
-    #       :error = Transmogrifier.handle_incoming(accept_data)
+      {:ok, follower} = Actors.get_actor_by_url(follower.url)
 
-    #       follower = Repo.get(User, follower.id)
+      refute Actor.following?(follower, followed)
+    end
 
-    #       refute User.following?(follower, followed) == true
-    #     end
+    test "it works for incoming rejects which are referenced by IRI only" do
+      follower = insert(:actor)
+      followed = insert(:actor)
 
-    #     test "it fails for incoming rejects which cannot be correlated" do
-    #       follower = insert(:user)
-    #       followed = insert(:user, %{info: %{"locked" => true}})
+      {:ok, follow_activity, _} = ActivityPub.follow(follower, followed)
 
-    #       accept_data =
-    #         File.read!("test/fixtures/mastodon-reject-activity.json")
-    #         |> Jason.decode!()
-    #         |> Map.put("actor", followed.ap_id)
+      assert Actor.following?(follower, followed)
 
-    #       accept_data =
-    #         Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
+      reject_data =
+        File.read!("test/fixtures/mastodon-reject-activity.json")
+        |> Jason.decode!()
+        |> Map.put("actor", followed.url)
+        |> Map.put("object", follow_activity.data["id"])
 
-    #       :error = Transmogrifier.handle_incoming(accept_data)
+      {:ok, %Activity{data: _}, _} = Transmogrifier.handle_incoming(reject_data)
 
-    #       follower = Repo.get(User, follower.id)
+      refute Actor.following?(follower, followed)
+    end
 
-    #       refute User.following?(follower, followed) == true
-    #     end
+    test "it rejects activities without a valid ID" do
+      actor = insert(:actor)
 
-    #     test "it works for incoming rejects which are orphaned" do
-    #       follower = insert(:user)
-    #       followed = insert(:user, %{info: %{"locked" => true}})
+      data =
+        File.read!("test/fixtures/mastodon-follow-activity.json")
+        |> Jason.decode!()
+        |> Map.put("object", actor.url)
+        |> Map.put("id", "")
 
-    #       {:ok, follower} = User.follow(follower, followed)
-    #       {:ok, _follow_activity} = ActivityPub.follow(follower, followed)
-
-    #       assert User.following?(follower, followed) == true
-
-    #       reject_data =
-    #         File.read!("test/fixtures/mastodon-reject-activity.json")
-    #         |> Jason.decode!()
-    #         |> Map.put("actor", followed.ap_id)
-
-    #       reject_data =
-    #         Map.put(reject_data, "object", Map.put(reject_data["object"], "actor", follower.ap_id))
-
-    #       {:ok, activity} = Transmogrifier.handle_incoming(reject_data)
-    #       refute activity.local
-
-    #       follower = Repo.get(User, follower.id)
-
-    #       assert User.following?(follower, followed) == false
-    #     end
-
-    #     test "it works for incoming rejects which are referenced by IRI only" do
-    #       follower = insert(:user)
-    #       followed = insert(:user, %{info: %{"locked" => true}})
-
-    #       {:ok, follower} = User.follow(follower, followed)
-    #       {:ok, follow_activity} = ActivityPub.follow(follower, followed)
-
-    #       assert User.following?(follower, followed) == true
-
-    #       reject_data =
-    #         File.read!("test/fixtures/mastodon-reject-activity.json")
-    #         |> Jason.decode!()
-    #         |> Map.put("actor", followed.ap_id)
-    #         |> Map.put("object", follow_activity.data["id"])
-
-    #       {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
-
-    #       follower = Repo.get(User, follower.id)
-
-    #       assert User.following?(follower, followed) == false
-    #     end
-
-    #     test "it rejects activities without a valid ID" do
-    #       user = insert(:user)
-
-    #       data =
-    #         File.read!("test/fixtures/mastodon-follow-activity.json")
-    #         |> Jason.decode!()
-    #         |> Map.put("object", user.ap_id)
-    #         |> Map.put("id", "")
-
-    #       :error = Transmogrifier.handle_incoming(data)
-    #     end
+      :error = Transmogrifier.handle_incoming(data)
+    end
 
     test "it accepts Flag activities" do
       %Actor{url: reporter_url} = _reporter = insert(:actor)
diff --git a/test/mobilizon_web/controllers/activity_pub_controller_test.exs b/test/mobilizon_web/controllers/activity_pub_controller_test.exs
index 894d5768c..df97d7763 100644
--- a/test/mobilizon_web/controllers/activity_pub_controller_test.exs
+++ b/test/mobilizon_web/controllers/activity_pub_controller_test.exs
@@ -279,6 +279,28 @@ defmodule MobilizonWeb.ActivityPubControllerTest do
     end
   end
 
+  describe "/relay" do
+    test "with the relay active, it returns the relay user", %{conn: conn} do
+      res =
+        conn
+        |> get(activity_pub_path(conn, :relay))
+        |> json_response(200)
+
+      assert res["id"] =~ "/relay"
+    end
+
+    test "with the relay disabled, it returns 404", %{conn: conn} do
+      Mobilizon.CommonConfig.put([:instance, :allow_relay], false)
+
+      conn
+      |> get(activity_pub_path(conn, :relay))
+      |> json_response(404)
+      |> assert
+
+      Mobilizon.CommonConfig.put([:instance, :allow_relay], true)
+    end
+  end
+
   #
   #  describe "/@:preferred_username/following" do
   #    test "it returns the following in a collection", %{conn: conn} do
diff --git a/test/support/factory.ex b/test/support/factory.ex
index b8ee13cf4..5d0d4bedf 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -39,6 +39,7 @@ defmodule Mobilizon.Factory do
       url: Actor.build_url(preferred_username, :page),
       followers_url: Actor.build_url(preferred_username, :followers),
       following_url: Actor.build_url(preferred_username, :following),
+      inbox_url: Actor.build_url(preferred_username, :inbox),
       outbox_url: Actor.build_url(preferred_username, :outbox),
       user: nil
     }
@@ -54,9 +55,13 @@ defmodule Mobilizon.Factory do
   end
 
   def follower_factory do
+    uuid = Ecto.UUID.generate()
+
     %Mobilizon.Actors.Follower{
       target_actor: build(:actor),
-      actor: build(:actor)
+      actor: build(:actor),
+      id: uuid,
+      url: "#{MobilizonWeb.Endpoint.url()}/follows/#{uuid}"
     }
   end
 
@@ -118,6 +123,7 @@ defmodule Mobilizon.Factory do
       visibility: :public,
       tags: build_list(3, :tag),
       url: Routes.page_url(Endpoint, :event, uuid),
+      picture: insert(:picture),
       uuid: uuid
     }
   end
diff --git a/test/tasks/relay_test.exs b/test/tasks/relay_test.exs
new file mode 100644
index 000000000..f35a0a5f4
--- /dev/null
+++ b/test/tasks/relay_test.exs
@@ -0,0 +1,47 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Mix.Tasks.Mobilizon.RelayTest do
+  alias Mobilizon.Actors.{Actor, Follower}
+  alias Mobilizon.Actors
+  alias Mobilizon.Service.ActivityPub.Relay
+  use Mobilizon.DataCase
+  use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
+
+  describe "running follow" do
+    test "relay is followed" do
+      use_cassette "relay/fetch_relay_follow" do
+        target_instance = "http://localhost:8080/actor"
+
+        Mix.Tasks.Mobilizon.Relay.run(["follow", target_instance])
+
+        local_actor = Relay.get_actor()
+        assert local_actor.url =~ "/relay"
+
+        {:ok, target_actor} = Actors.get_actor_by_url(target_instance)
+        refute is_nil(target_actor.domain)
+
+        assert Actor.following?(local_actor, target_actor)
+      end
+    end
+  end
+
+  describe "running unfollow" do
+    test "relay is unfollowed" do
+      use_cassette "relay/fetch_relay_unfollow" do
+        target_instance = "http://localhost:8080/actor"
+
+        Mix.Tasks.Mobilizon.Relay.run(["follow", target_instance])
+
+        %Actor{} = local_actor = Relay.get_actor()
+        {:ok, %Actor{} = target_actor} = Actors.get_actor_by_url(target_instance)
+        assert %Follower{} = Actor.following?(local_actor, target_actor)
+
+        Mix.Tasks.Mobilizon.Relay.run(["unfollow", target_instance])
+
+        refute Actor.following?(local_actor, target_actor)
+      end
+    end
+  end
+end