├── .gitignore ├── README.md ├── assets ├── css │ └── application.css └── js │ ├── TurboStreamWebsocketSource.js │ └── index.js ├── controllers ├── controllers.go ├── doc.go ├── message.go └── room.go ├── go.mod ├── go.sum ├── main.go ├── models ├── doc.go ├── message.go ├── models.go └── room.go ├── package-lock.json ├── package.json ├── pkg ├── notice │ └── notice.go ├── pubsub │ └── pubsub.go └── timefmt │ └── timefmt.go ├── routes └── route.go ├── scripts ├── bootstrap.sh └── setup.sh ├── templates ├── layout.gohtml ├── messages │ ├── _message.gohtml │ ├── create.turbostream.gohtml │ └── new.gohtml └── rooms │ ├── _form.gohtml │ ├── _room.gohtml │ ├── edit.gohtml │ ├── index.gohtml │ ├── new.gohtml │ └── show.gohtml └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public/ 3 | .vscode/ 4 | *.db 5 | *.log 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hotwire Go Example 2 | 3 | This is a recreation of the [Hotwire Rails Demo Chat](https://github.com/hotwired/hotwire-rails-demo-chat) with a Go backend. 4 | See the [Hotwire docs](https://hotwire.dev) for more information about Hotwire. 5 | 6 | ## Quickstart 7 | 8 | ### Requirements 9 | 10 | * Go 11 | * NPM 12 | 13 | ### Set up the project 14 | 15 | #### Automatic 16 | 17 | Run `./scripts/setup.sh`. 18 | 19 | #### Manual 20 | 21 | 1. Download Go dependencies: `go mod download` 22 | 1. Download node dependencies: `npm install` 23 | 1. Create a webpack bundle: `npx webpack -c webpack.config.js` 24 | 25 | ### Run the project 26 | 27 | The demo can be run with `go run main.go` from the project root. 28 | 29 | ## Packages used 30 | 31 | Ruby On Rails provides a wealth of functionality out of the box. 32 | While batteries-included frameworks for Go web development exist (e.g. [Buffalo](https://gobuffalo.io)), 33 | it's often more idiomatic to compose functionality from small, single-purpose libraries. 34 | In order to mimic some of Rails' functionality, the following packages were used: 35 | 36 | * [Chi](https://github.com/go-chi/chi) provides request routing and middleware support. 37 | * [Render](https://github.com/unrolled/render) provides template rendering. 38 | * [GORM](https://gorm.io) provides database ORM functionality. 39 | * [Websocket](https://nhooyr.io/websocket) provides websocket connectivity. 40 | 41 | In addition, the `pkg` directory contains a few purpose-built packages that mimic Rails functionality for the demo: 42 | 43 | * `pubsub` implements in-memory PubSub functionality that fills the role of Rails' [ActionCable](https://edgeguides.rubyonrails.org/action_cable_overview.html). 44 | * `notify` implements a cookie-based notification banner. 45 | * `timefmt` implements a helper function for formatting Go's `time.Time` type into a similar format to the Rails example. 46 | 47 | ## Notable differences from the Rails demo 48 | 49 | * The Rails demo uses a [Stimulus controller](https://stimulus.hotwire.dev) to do form resetting when submitting a new chat message. 50 | While Stimulus is a great framework, in Go it's generally idiomatic to reimplement small pieces of functionality instead of adding a new dependency, and because the reset controller functionality is easily implemented in pure Javascript, it felt more idiomatic to leave Stimulus out in this case. 51 | * [Turbo Rails](https://github.com/hotwired/turbo-rails), and the Rails example by extension, relies heavily on `ActionCable` to connect Turbo Streams to a websocket. 52 | Because there is no ActionCable equivalent in Go, this example uses an in-memory pubsub mechanism and a `TurboStreamWebsocketSource` [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) to mimic the same functionality. 53 | In a production setting, you would probably want to use a more robust PubSub mechanism. -------------------------------------------------------------------------------- /assets/css/application.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #333; 4 | margin: 33px; 5 | } 6 | 7 | body, 8 | p, 9 | ol, 10 | ul, 11 | td { 12 | font-family: verdana, arial, helvetica, sans-serif; 13 | font-size: 13px; 14 | line-height: 18px; 15 | } 16 | 17 | pre { 18 | background-color: #eee; 19 | padding: 10px; 20 | font-size: 11px; 21 | } 22 | 23 | a { 24 | color: #000; 25 | } 26 | 27 | a:visited { 28 | color: #666; 29 | } 30 | 31 | a:hover { 32 | color: #fff; 33 | background-color: #000; 34 | } 35 | 36 | th { 37 | padding-bottom: 5px; 38 | } 39 | 40 | td { 41 | padding: 0 5px 7px; 42 | } 43 | 44 | div.field, 45 | div.actions { 46 | margin-bottom: 10px; 47 | } 48 | 49 | #notice { 50 | color: green; 51 | } 52 | 53 | .field_with_errors { 54 | padding: 2px; 55 | background-color: red; 56 | display: table; 57 | } 58 | 59 | #error_explanation { 60 | width: 450px; 61 | border: 2px solid red; 62 | padding: 7px 7px 0; 63 | margin-bottom: 20px; 64 | background-color: #f0f0f0; 65 | } 66 | 67 | #error_explanation h2 { 68 | text-align: left; 69 | font-weight: bold; 70 | padding: 5px 5px 5px 15px; 71 | font-size: 12px; 72 | margin: -7px -7px 0; 73 | background-color: #c00; 74 | color: #fff; 75 | } 76 | 77 | #error_explanation ul li { 78 | font-size: 12px; 79 | list-style: square; 80 | } 81 | 82 | label { 83 | display: block; 84 | } 85 | 86 | turbo-frame { 87 | display: block; 88 | border: 1px solid blue; 89 | } 90 | -------------------------------------------------------------------------------- /assets/js/TurboStreamWebsocketSource.js: -------------------------------------------------------------------------------- 1 | import { connectStreamSource, disconnectStreamSource } from "@hotwired/turbo"; 2 | 3 | /** 4 | * Creates a persistent connection to a websocket for use with Turbo Streams 5 | */ 6 | export default class TurboStreamWebsocketSource extends HTMLElement { 7 | get src() { 8 | return this.getAttribute("src"); 9 | } 10 | 11 | set src(value) { 12 | if (value) { 13 | this.setAttribute("src", value); 14 | } else { 15 | this.removeAttribute("src"); 16 | } 17 | } 18 | 19 | /** 20 | * Called when the element is inserted into the DOM. 21 | * Connects to Turbo Streams as a source and sets up the websocket connection 22 | * for streaming updates to turbo streams 23 | */ 24 | async connectedCallback() { 25 | connectStreamSource(this); 26 | this.ws = this.setupWebsocket(); 27 | } 28 | 29 | /** 30 | * Called when the element is removed from the DOM. 31 | * Disconnects from Turbo Streams and deletes the WebSocket 32 | */ 33 | disconnectedCallback() { 34 | disconnectStreamSource(this); 35 | if (this.ws) { 36 | this.ws = null; 37 | } 38 | } 39 | 40 | /** 41 | * Called in response to a websocket message. Unpacks the websocket message 42 | * and dispatches it as a new MessageEvent to Turbo Streams. 43 | * 44 | * @param {MessageEvent} messageEvent The original message to dispatch 45 | */ 46 | dispatchMessageEvent(messageEvent) { 47 | const event = new MessageEvent("message", { data: messageEvent.data }); 48 | this.dispatchEvent(event); 49 | } 50 | 51 | /** 52 | * Creates a WebSocket by combining the window host and the element's src attribute and wires it to dispatch messages 53 | */ 54 | setupWebsocket() { 55 | let socketLocation = `ws://${window.location.host}${this.src}` 56 | let ws = new WebSocket(socketLocation); 57 | ws.onmessage = (msg) => { 58 | this.dispatchMessageEvent(msg); 59 | }; 60 | return ws; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /assets/js/index.js: -------------------------------------------------------------------------------- 1 | import TurboStreamWebsocketSource from "./TurboStreamWebsocketSource"; 2 | 3 | window.onload = () => { 4 | // This was implemented using a Stimulus controller in the original Rails 5 | // example. Clears the new message form on send. 6 | addEventListener("turbo:submit-end", () => { 7 | document.getElementById("new-message-form").reset(); 8 | }); 9 | 10 | customElements.define( 11 | "turbo-stream-websocket-source", 12 | TurboStreamWebsocketSource 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /controllers/controllers.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "html/template" 5 | 6 | unrolledRender "github.com/unrolled/render" 7 | 8 | "github.com/while1malloc0/hotwire-go-example/pkg/timefmt" 9 | ) 10 | 11 | var render = unrolledRender.New( 12 | unrolledRender.Options{ 13 | Extensions: []string{".gohtml"}, 14 | Layout: "layout", 15 | Funcs: []template.FuncMap{timefmt.FuncMap}, 16 | }, 17 | ) 18 | -------------------------------------------------------------------------------- /controllers/doc.go: -------------------------------------------------------------------------------- 1 | // Package controllers implements the Controller functionality in a 2 | // Model/View/Controller architecture. 3 | // 4 | // Controllers are responsible for responding to web requests. 5 | package controllers 6 | -------------------------------------------------------------------------------- /controllers/message.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "bytes" 5 | "net/http" 6 | 7 | "github.com/while1malloc0/hotwire-go-example/models" 8 | "github.com/while1malloc0/hotwire-go-example/pkg/pubsub" 9 | "nhooyr.io/websocket" 10 | ) 11 | 12 | // MessagesController implements Controller functionality for the Message model 13 | type MessagesController struct{} 14 | 15 | // New renders a form for creating a new Message 16 | func (*MessagesController) New(w http.ResponseWriter, r *http.Request) { 17 | room := r.Context().Value(ContextKeyRoom).(*models.Room) 18 | responseData := map[string]interface{}{"Room": room} 19 | render.HTML(w, http.StatusOK, "messages/new", responseData) 20 | } 21 | 22 | // Create creates a new Message 23 | func (*MessagesController) Create(w http.ResponseWriter, r *http.Request) { 24 | err := r.ParseMultipartForm(1024) 25 | if err != nil { 26 | http.Error(w, err.Error(), http.StatusInternalServerError) 27 | } 28 | 29 | room := r.Context().Value(ContextKeyRoom).(*models.Room) 30 | message := &models.Message{ 31 | Content: r.FormValue("message[content]"), 32 | Room: *room, 33 | } 34 | 35 | err = models.CreateMessage(message) 36 | 37 | if err != nil { 38 | http.Error(w, err.Error(), http.StatusInternalServerError) 39 | } 40 | 41 | w.Header().Add("Content-Type", "text/html; turbo-stream; charset=utf-8") 42 | var content bytes.Buffer 43 | responseData := map[string]interface{}{"Message": message} 44 | err = render.HTML(&content, http.StatusCreated, "messages/create.turbostream", responseData) 45 | if err != nil { 46 | http.Error(w, err.Error(), http.StatusInternalServerError) 47 | } 48 | 49 | pubsub.Publish(room.ID, content.Bytes()) 50 | } 51 | 52 | // Socket opens a persistent WebSocket connection and subscribes it for updates to its room 53 | func (*MessagesController) Socket(w http.ResponseWriter, r *http.Request) { 54 | ws, err := websocket.Accept(w, r, nil) 55 | if err != nil { 56 | http.Error(w, err.Error(), http.StatusInternalServerError) 57 | return 58 | } 59 | room := r.Context().Value(ContextKeyRoom).(*models.Room) 60 | pubsub.Subscribe(room.ID, ws) 61 | } 62 | -------------------------------------------------------------------------------- /controllers/room.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "strconv" 8 | 9 | "github.com/go-chi/chi" 10 | "github.com/while1malloc0/hotwire-go-example/models" 11 | "github.com/while1malloc0/hotwire-go-example/pkg/notice" 12 | ) 13 | 14 | type contextKey struct{} 15 | 16 | var ( 17 | // ContextKeyRoom is a type safe representation of the key "room" inside of a context.Context 18 | ContextKeyRoom = contextKey{} 19 | ) 20 | 21 | // RoomsController implements Controller functionality for the Room model 22 | type RoomsController struct{} 23 | 24 | // Context is a middleware that parses the Room ID from a request, loads the 25 | // corresponding Room model, and makes it available as part of the request's 26 | // context 27 | func (*RoomsController) Context(next http.Handler) http.Handler { 28 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 29 | var room *models.Room 30 | var err error 31 | if idStr := chi.URLParam(r, "id"); idStr != "" { 32 | room, err = roomFromIDString(idStr) 33 | } 34 | if models.IsRecordNotFound(err) { 35 | http.Error(w, "Room not found", http.StatusNotFound) 36 | return 37 | } 38 | if err != nil { 39 | http.Error(w, fmt.Sprintf("Fatal error: %v", err), http.StatusInternalServerError) 40 | return 41 | } 42 | 43 | ctx := context.WithValue(r.Context(), ContextKeyRoom, room) 44 | next.ServeHTTP(w, r.WithContext(ctx)) 45 | }) 46 | } 47 | 48 | func roomFromIDString(idStr string) (*models.Room, error) { 49 | id, err := strconv.ParseUint(idStr, 10, 64) 50 | if err != nil { 51 | return nil, err 52 | } 53 | room, err := models.FindRoom(id) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return room, nil 58 | } 59 | 60 | // Index shows a list of all Rooms 61 | func (*RoomsController) Index(w http.ResponseWriter, r *http.Request) { 62 | rooms, err := models.ListRooms() 63 | if err != nil { 64 | http.Error(w, err.Error(), http.StatusInternalServerError) 65 | return 66 | } 67 | notice := r.Context().Value(notice.ContextKey) 68 | responseData := map[string]interface{}{"Rooms": rooms, "Notice": notice} 69 | render.HTML(w, http.StatusOK, "rooms/index", responseData) 70 | } 71 | 72 | // New renders a form for creating a new Room 73 | func (*RoomsController) New(w http.ResponseWriter, r *http.Request) { 74 | render.HTML(w, http.StatusOK, "rooms/new", nil) 75 | } 76 | 77 | // Edit renders a form for making changes to an existing Room 78 | func (*RoomsController) Edit(w http.ResponseWriter, r *http.Request) { 79 | room := r.Context().Value(ContextKeyRoom).(*models.Room) 80 | responseData := map[string]interface{}{"Room": room} 81 | render.HTML(w, http.StatusOK, "rooms/edit", responseData) 82 | } 83 | 84 | // Get retrieves a single Room by its ID 85 | func (*RoomsController) Get(w http.ResponseWriter, r *http.Request) { 86 | room := r.Context().Value(ContextKeyRoom).(*models.Room) 87 | responseData := map[string]interface{}{"Room": room} 88 | render.HTML(w, http.StatusOK, "rooms/show", responseData) 89 | } 90 | 91 | // Update makes changes to a Room given its ID 92 | func (*RoomsController) Update(w http.ResponseWriter, r *http.Request) { 93 | room := r.Context().Value(ContextKeyRoom).(*models.Room) 94 | err := r.ParseMultipartForm(1024) 95 | if err != nil { 96 | http.Error(w, err.Error(), http.StatusInternalServerError) 97 | return 98 | } 99 | 100 | name := r.FormValue("room[name]") 101 | updates := map[string]interface{}{ 102 | "Name": name, 103 | } 104 | err = models.UpdateRoom(room, updates) 105 | if err != nil { 106 | http.Error(w, err.Error(), http.StatusInternalServerError) 107 | return 108 | } 109 | 110 | http.Redirect(w, r, fmt.Sprintf("/rooms/%d", room.ID), http.StatusFound) 111 | } 112 | 113 | // Create makes a new Room 114 | func (*RoomsController) Create(w http.ResponseWriter, r *http.Request) { 115 | err := r.ParseMultipartForm(1024) 116 | if err != nil { 117 | http.Error(w, err.Error(), http.StatusInternalServerError) 118 | return 119 | } 120 | name := r.FormValue("room[name]") 121 | err = models.CreateRoom(name) 122 | if err != nil { 123 | http.Error(w, err.Error(), http.StatusInternalServerError) 124 | return 125 | } 126 | 127 | notice.Set(w, "Room created successfully") 128 | http.Redirect(w, r, "/rooms", http.StatusFound) 129 | } 130 | 131 | // Destroy deletes an existing room 132 | func (*RoomsController) Destroy(w http.ResponseWriter, r *http.Request) { 133 | room := r.Context().Value(ContextKeyRoom).(*models.Room) 134 | err := models.DeleteRoom(room) 135 | if err != nil { 136 | http.Error(w, err.Error(), http.StatusInternalServerError) 137 | return 138 | } 139 | 140 | notice.Set(w, "Room deleted successfully") 141 | http.Redirect(w, r, "/rooms", http.StatusFound) 142 | } 143 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/while1malloc0/hotwire-go-example 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/go-chi/chi v1.5.1 7 | github.com/mattn/go-sqlite3 v1.14.6 // indirect 8 | github.com/unrolled/render v1.0.3 9 | gopkg.in/yaml.v2 v2.3.0 // indirect 10 | gorm.io/driver/sqlite v1.1.4 11 | gorm.io/gorm v1.20.9 12 | nhooyr.io/websocket v1.8.6 13 | ) 14 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= 5 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= 6 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 7 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 8 | github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= 9 | github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= 10 | github.com/go-chi/chi v1.5.1 h1:kfTK3Cxd/dkMu/rKs5ZceWYp+t5CtiE7vmaTv3LjC6w= 11 | github.com/go-chi/chi v1.5.1/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k= 12 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 13 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 14 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 15 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 16 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 17 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 18 | github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= 19 | github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= 20 | github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= 21 | github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= 22 | github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= 23 | github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= 24 | github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= 25 | github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= 26 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 27 | github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= 28 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 29 | github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= 30 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 31 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 32 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= 33 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 34 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 35 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 36 | github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= 37 | github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 38 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 39 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 40 | github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8= 41 | github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 42 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 43 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 44 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 45 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 46 | github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= 47 | github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= 48 | github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= 49 | github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 50 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 51 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 52 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 53 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 54 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 55 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 56 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 57 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 58 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 59 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 60 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 61 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 62 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 63 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 64 | github.com/unrolled/render v1.0.3 h1:baO+NG1bZSF2WR4zwh+0bMWauWky7DVrTOfvE2w+aFo= 65 | github.com/unrolled/render v1.0.3/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM= 66 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 67 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 68 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 69 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 70 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 71 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 72 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 73 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 74 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 75 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 76 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 77 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 78 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 79 | gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= 80 | gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= 81 | gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= 82 | gorm.io/gorm v1.20.9 h1:M3aIZKXAC1PtPVu9t3WGwkBTE1le5c2telz3I/qjRNg= 83 | gorm.io/gorm v1.20.9/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= 84 | nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= 85 | nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= 86 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | "strconv" 9 | 10 | "github.com/go-chi/chi" 11 | "github.com/go-chi/chi/middleware" 12 | "github.com/while1malloc0/hotwire-go-example/models" 13 | "github.com/while1malloc0/hotwire-go-example/routes" 14 | ) 15 | 16 | func main() { 17 | log.Println("Starting app") 18 | 19 | setupDB() 20 | 21 | router := registerRoutes() 22 | 23 | port := getPort() 24 | log.Printf("Serving on port %d", port) 25 | 26 | if err := http.ListenAndServe(fmt.Sprintf(":%d", port), router); err != nil { 27 | log.Fatal(err) 28 | } 29 | } 30 | 31 | func registerRoutes() http.Handler { 32 | log.Println("Registering routes") 33 | r := chi.NewMux() 34 | r.Use(middleware.Logger) 35 | r.Use(middleware.Recoverer) 36 | routes.Register(r) 37 | 38 | r.Handle("/public/*", http.StripPrefix("/public/", http.FileServer(http.Dir("./public")))) 39 | 40 | logRoutes(r) 41 | 42 | return r 43 | } 44 | 45 | func logRoutes(r chi.Router) { 46 | log.Println("Serving with routes") 47 | chi.Walk(r, func(method, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error { 48 | log.Println(method, route) 49 | return nil 50 | }) 51 | } 52 | 53 | func setupDB() { 54 | log.Println("Running migrations") 55 | err := models.Migrate() 56 | if err != nil { 57 | log.Fatalf("Fatal error: %v", err) 58 | } 59 | 60 | log.Println("Seeding database") 61 | err = models.Seed() 62 | if err != nil { 63 | log.Fatalf("Fatal error: %v", err) 64 | } 65 | } 66 | 67 | func getPort() int { 68 | port := 8080 69 | if p, ok := os.LookupEnv("HOTWIRE_CHAT_PORT"); ok { 70 | parsed, err := strconv.Atoi(p) 71 | if err != nil { 72 | log.Fatalf("Fatal error: %v", err) 73 | } 74 | port = parsed 75 | } 76 | return port 77 | } 78 | -------------------------------------------------------------------------------- /models/doc.go: -------------------------------------------------------------------------------- 1 | // Package models implements the Model functionality in a Model/View/Controller architecture. 2 | package models 3 | -------------------------------------------------------------------------------- /models/message.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "gorm.io/gorm" 4 | 5 | // Message represents a chat message inside of a Room 6 | type Message struct { 7 | gorm.Model 8 | 9 | Room Room 10 | RoomID int 11 | 12 | Content string 13 | } 14 | 15 | // CreateMessage persists a new Message to the Database 16 | func CreateMessage(message *Message) error { 17 | tx := DB.Create(message) 18 | return tx.Error 19 | } 20 | -------------------------------------------------------------------------------- /models/models.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | 6 | "gorm.io/driver/sqlite" 7 | "gorm.io/gorm" 8 | ) 9 | 10 | // DB is a connection to the Database 11 | var DB *gorm.DB 12 | 13 | func init() { 14 | var err error 15 | if DB == nil { 16 | DB, err = gorm.Open(sqlite.Open("chat.db"), &gorm.Config{}) 17 | } 18 | if err != nil { 19 | panic(err) 20 | } 21 | } 22 | 23 | // Migrate runs migrations for all models. 24 | func Migrate() error { 25 | return DB.AutoMigrate(Room{}, Message{}) 26 | } 27 | 28 | // IsRecordNotFound determines if an error was caused by a database transaction 29 | // returning no records 30 | func IsRecordNotFound(err error) bool { 31 | return errors.Is(err, gorm.ErrRecordNotFound) 32 | } 33 | 34 | // Seed creates test records in the database 35 | func Seed() error { 36 | var room Room 37 | testRoomName := "Test Room" 38 | if DB.Where(&Room{Name: testRoomName}).First(&room); room.ID == 0 { 39 | if tx := DB.Create(&Room{Name: testRoomName}); tx.Error != nil { 40 | return tx.Error 41 | } 42 | } 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /models/room.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | ) 6 | 7 | // Room represents a chat room 8 | type Room struct { 9 | gorm.Model 10 | 11 | Name string 12 | Messages []Message 13 | } 14 | 15 | // CreateRoom persists a new Room with the given name to the database 16 | func CreateRoom(name string) error { 17 | tx := DB.Create(&Room{Name: name}) 18 | return tx.Error 19 | } 20 | 21 | // FindRoom attempts to lookup a room by its ID 22 | func FindRoom(id uint64) (*Room, error) { 23 | var room Room 24 | tx := DB.First(&room, id) 25 | if tx.Error != nil { 26 | return nil, tx.Error 27 | } 28 | 29 | DB.Model(&room).Association("Messages").Find(&room.Messages) 30 | 31 | return &room, nil 32 | } 33 | 34 | // ListRooms retrieves a list of all Rooms from the database 35 | func ListRooms() ([]*Room, error) { 36 | rows, err := DB.Model(&Room{}).Rows() 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | var rooms []*Room 42 | for rows.Next() { 43 | var room Room 44 | DB.ScanRows(rows, &room) 45 | rooms = append(rooms, &room) 46 | } 47 | 48 | return rooms, nil 49 | } 50 | 51 | // UpdateRoom makes changes to an existing Room given a map of column:value pairs 52 | // e.g. map[string]interface{}{"name": "some new name"} 53 | func UpdateRoom(room *Room, updates map[string]interface{}) error { 54 | tx := DB.First(room, room.ID).Updates(updates) 55 | return tx.Error 56 | } 57 | 58 | // DeleteRoom deletes an existing Room 59 | func DeleteRoom(room *Room) error { 60 | tx := DB.Delete(room) 61 | return tx.Error 62 | } 63 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hotwire-go-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.12.11", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", 10 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", 11 | "requires": { 12 | "@babel/highlight": "^7.10.4" 13 | } 14 | }, 15 | "@babel/compat-data": { 16 | "version": "7.12.7", 17 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", 18 | "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==" 19 | }, 20 | "@babel/core": { 21 | "version": "7.12.10", 22 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz", 23 | "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", 24 | "requires": { 25 | "@babel/code-frame": "^7.10.4", 26 | "@babel/generator": "^7.12.10", 27 | "@babel/helper-module-transforms": "^7.12.1", 28 | "@babel/helpers": "^7.12.5", 29 | "@babel/parser": "^7.12.10", 30 | "@babel/template": "^7.12.7", 31 | "@babel/traverse": "^7.12.10", 32 | "@babel/types": "^7.12.10", 33 | "convert-source-map": "^1.7.0", 34 | "debug": "^4.1.0", 35 | "gensync": "^1.0.0-beta.1", 36 | "json5": "^2.1.2", 37 | "lodash": "^4.17.19", 38 | "semver": "^5.4.1", 39 | "source-map": "^0.5.0" 40 | }, 41 | "dependencies": { 42 | "semver": { 43 | "version": "5.7.1", 44 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 45 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 46 | }, 47 | "source-map": { 48 | "version": "0.5.7", 49 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 50 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" 51 | } 52 | } 53 | }, 54 | "@babel/generator": { 55 | "version": "7.12.11", 56 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", 57 | "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", 58 | "requires": { 59 | "@babel/types": "^7.12.11", 60 | "jsesc": "^2.5.1", 61 | "source-map": "^0.5.0" 62 | }, 63 | "dependencies": { 64 | "source-map": { 65 | "version": "0.5.7", 66 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 67 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" 68 | } 69 | } 70 | }, 71 | "@babel/helper-annotate-as-pure": { 72 | "version": "7.12.10", 73 | "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz", 74 | "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==", 75 | "requires": { 76 | "@babel/types": "^7.12.10" 77 | } 78 | }, 79 | "@babel/helper-builder-binary-assignment-operator-visitor": { 80 | "version": "7.10.4", 81 | "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", 82 | "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", 83 | "requires": { 84 | "@babel/helper-explode-assignable-expression": "^7.10.4", 85 | "@babel/types": "^7.10.4" 86 | } 87 | }, 88 | "@babel/helper-compilation-targets": { 89 | "version": "7.12.5", 90 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", 91 | "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", 92 | "requires": { 93 | "@babel/compat-data": "^7.12.5", 94 | "@babel/helper-validator-option": "^7.12.1", 95 | "browserslist": "^4.14.5", 96 | "semver": "^5.5.0" 97 | }, 98 | "dependencies": { 99 | "semver": { 100 | "version": "5.7.1", 101 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 102 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 103 | } 104 | } 105 | }, 106 | "@babel/helper-create-class-features-plugin": { 107 | "version": "7.12.1", 108 | "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", 109 | "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", 110 | "requires": { 111 | "@babel/helper-function-name": "^7.10.4", 112 | "@babel/helper-member-expression-to-functions": "^7.12.1", 113 | "@babel/helper-optimise-call-expression": "^7.10.4", 114 | "@babel/helper-replace-supers": "^7.12.1", 115 | "@babel/helper-split-export-declaration": "^7.10.4" 116 | } 117 | }, 118 | "@babel/helper-create-regexp-features-plugin": { 119 | "version": "7.12.7", 120 | "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", 121 | "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", 122 | "requires": { 123 | "@babel/helper-annotate-as-pure": "^7.10.4", 124 | "regexpu-core": "^4.7.1" 125 | } 126 | }, 127 | "@babel/helper-define-map": { 128 | "version": "7.10.5", 129 | "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", 130 | "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", 131 | "requires": { 132 | "@babel/helper-function-name": "^7.10.4", 133 | "@babel/types": "^7.10.5", 134 | "lodash": "^4.17.19" 135 | } 136 | }, 137 | "@babel/helper-explode-assignable-expression": { 138 | "version": "7.12.1", 139 | "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", 140 | "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", 141 | "requires": { 142 | "@babel/types": "^7.12.1" 143 | } 144 | }, 145 | "@babel/helper-function-name": { 146 | "version": "7.12.11", 147 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", 148 | "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", 149 | "requires": { 150 | "@babel/helper-get-function-arity": "^7.12.10", 151 | "@babel/template": "^7.12.7", 152 | "@babel/types": "^7.12.11" 153 | } 154 | }, 155 | "@babel/helper-get-function-arity": { 156 | "version": "7.12.10", 157 | "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", 158 | "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", 159 | "requires": { 160 | "@babel/types": "^7.12.10" 161 | } 162 | }, 163 | "@babel/helper-hoist-variables": { 164 | "version": "7.10.4", 165 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", 166 | "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", 167 | "requires": { 168 | "@babel/types": "^7.10.4" 169 | } 170 | }, 171 | "@babel/helper-member-expression-to-functions": { 172 | "version": "7.12.7", 173 | "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", 174 | "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", 175 | "requires": { 176 | "@babel/types": "^7.12.7" 177 | } 178 | }, 179 | "@babel/helper-module-imports": { 180 | "version": "7.12.5", 181 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", 182 | "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", 183 | "requires": { 184 | "@babel/types": "^7.12.5" 185 | } 186 | }, 187 | "@babel/helper-module-transforms": { 188 | "version": "7.12.1", 189 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", 190 | "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", 191 | "requires": { 192 | "@babel/helper-module-imports": "^7.12.1", 193 | "@babel/helper-replace-supers": "^7.12.1", 194 | "@babel/helper-simple-access": "^7.12.1", 195 | "@babel/helper-split-export-declaration": "^7.11.0", 196 | "@babel/helper-validator-identifier": "^7.10.4", 197 | "@babel/template": "^7.10.4", 198 | "@babel/traverse": "^7.12.1", 199 | "@babel/types": "^7.12.1", 200 | "lodash": "^4.17.19" 201 | } 202 | }, 203 | "@babel/helper-optimise-call-expression": { 204 | "version": "7.12.10", 205 | "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", 206 | "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", 207 | "requires": { 208 | "@babel/types": "^7.12.10" 209 | } 210 | }, 211 | "@babel/helper-plugin-utils": { 212 | "version": "7.10.4", 213 | "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", 214 | "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" 215 | }, 216 | "@babel/helper-remap-async-to-generator": { 217 | "version": "7.12.1", 218 | "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", 219 | "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", 220 | "requires": { 221 | "@babel/helper-annotate-as-pure": "^7.10.4", 222 | "@babel/helper-wrap-function": "^7.10.4", 223 | "@babel/types": "^7.12.1" 224 | } 225 | }, 226 | "@babel/helper-replace-supers": { 227 | "version": "7.12.11", 228 | "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", 229 | "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", 230 | "requires": { 231 | "@babel/helper-member-expression-to-functions": "^7.12.7", 232 | "@babel/helper-optimise-call-expression": "^7.12.10", 233 | "@babel/traverse": "^7.12.10", 234 | "@babel/types": "^7.12.11" 235 | } 236 | }, 237 | "@babel/helper-simple-access": { 238 | "version": "7.12.1", 239 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", 240 | "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", 241 | "requires": { 242 | "@babel/types": "^7.12.1" 243 | } 244 | }, 245 | "@babel/helper-skip-transparent-expression-wrappers": { 246 | "version": "7.12.1", 247 | "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", 248 | "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", 249 | "requires": { 250 | "@babel/types": "^7.12.1" 251 | } 252 | }, 253 | "@babel/helper-split-export-declaration": { 254 | "version": "7.12.11", 255 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", 256 | "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", 257 | "requires": { 258 | "@babel/types": "^7.12.11" 259 | } 260 | }, 261 | "@babel/helper-validator-identifier": { 262 | "version": "7.12.11", 263 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", 264 | "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" 265 | }, 266 | "@babel/helper-validator-option": { 267 | "version": "7.12.11", 268 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz", 269 | "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==" 270 | }, 271 | "@babel/helper-wrap-function": { 272 | "version": "7.12.3", 273 | "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", 274 | "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", 275 | "requires": { 276 | "@babel/helper-function-name": "^7.10.4", 277 | "@babel/template": "^7.10.4", 278 | "@babel/traverse": "^7.10.4", 279 | "@babel/types": "^7.10.4" 280 | } 281 | }, 282 | "@babel/helpers": { 283 | "version": "7.12.5", 284 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", 285 | "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", 286 | "requires": { 287 | "@babel/template": "^7.10.4", 288 | "@babel/traverse": "^7.12.5", 289 | "@babel/types": "^7.12.5" 290 | } 291 | }, 292 | "@babel/highlight": { 293 | "version": "7.10.4", 294 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", 295 | "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", 296 | "requires": { 297 | "@babel/helper-validator-identifier": "^7.10.4", 298 | "chalk": "^2.0.0", 299 | "js-tokens": "^4.0.0" 300 | } 301 | }, 302 | "@babel/parser": { 303 | "version": "7.12.11", 304 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", 305 | "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==" 306 | }, 307 | "@babel/plugin-proposal-async-generator-functions": { 308 | "version": "7.12.12", 309 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.12.tgz", 310 | "integrity": "sha512-nrz9y0a4xmUrRq51bYkWJIO5SBZyG2ys2qinHsN0zHDHVsUaModrkpyWWWXfGqYQmOL3x9sQIcTNN/pBGpo09A==", 311 | "requires": { 312 | "@babel/helper-plugin-utils": "^7.10.4", 313 | "@babel/helper-remap-async-to-generator": "^7.12.1", 314 | "@babel/plugin-syntax-async-generators": "^7.8.0" 315 | } 316 | }, 317 | "@babel/plugin-proposal-class-properties": { 318 | "version": "7.12.1", 319 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", 320 | "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", 321 | "requires": { 322 | "@babel/helper-create-class-features-plugin": "^7.12.1", 323 | "@babel/helper-plugin-utils": "^7.10.4" 324 | } 325 | }, 326 | "@babel/plugin-proposal-dynamic-import": { 327 | "version": "7.12.1", 328 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", 329 | "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", 330 | "requires": { 331 | "@babel/helper-plugin-utils": "^7.10.4", 332 | "@babel/plugin-syntax-dynamic-import": "^7.8.0" 333 | } 334 | }, 335 | "@babel/plugin-proposal-export-namespace-from": { 336 | "version": "7.12.1", 337 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", 338 | "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", 339 | "requires": { 340 | "@babel/helper-plugin-utils": "^7.10.4", 341 | "@babel/plugin-syntax-export-namespace-from": "^7.8.3" 342 | } 343 | }, 344 | "@babel/plugin-proposal-json-strings": { 345 | "version": "7.12.1", 346 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", 347 | "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", 348 | "requires": { 349 | "@babel/helper-plugin-utils": "^7.10.4", 350 | "@babel/plugin-syntax-json-strings": "^7.8.0" 351 | } 352 | }, 353 | "@babel/plugin-proposal-logical-assignment-operators": { 354 | "version": "7.12.1", 355 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", 356 | "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", 357 | "requires": { 358 | "@babel/helper-plugin-utils": "^7.10.4", 359 | "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" 360 | } 361 | }, 362 | "@babel/plugin-proposal-nullish-coalescing-operator": { 363 | "version": "7.12.1", 364 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", 365 | "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", 366 | "requires": { 367 | "@babel/helper-plugin-utils": "^7.10.4", 368 | "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" 369 | } 370 | }, 371 | "@babel/plugin-proposal-numeric-separator": { 372 | "version": "7.12.7", 373 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", 374 | "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", 375 | "requires": { 376 | "@babel/helper-plugin-utils": "^7.10.4", 377 | "@babel/plugin-syntax-numeric-separator": "^7.10.4" 378 | } 379 | }, 380 | "@babel/plugin-proposal-object-rest-spread": { 381 | "version": "7.12.1", 382 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", 383 | "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", 384 | "requires": { 385 | "@babel/helper-plugin-utils": "^7.10.4", 386 | "@babel/plugin-syntax-object-rest-spread": "^7.8.0", 387 | "@babel/plugin-transform-parameters": "^7.12.1" 388 | } 389 | }, 390 | "@babel/plugin-proposal-optional-catch-binding": { 391 | "version": "7.12.1", 392 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", 393 | "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", 394 | "requires": { 395 | "@babel/helper-plugin-utils": "^7.10.4", 396 | "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" 397 | } 398 | }, 399 | "@babel/plugin-proposal-optional-chaining": { 400 | "version": "7.12.7", 401 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", 402 | "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", 403 | "requires": { 404 | "@babel/helper-plugin-utils": "^7.10.4", 405 | "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", 406 | "@babel/plugin-syntax-optional-chaining": "^7.8.0" 407 | } 408 | }, 409 | "@babel/plugin-proposal-private-methods": { 410 | "version": "7.12.1", 411 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", 412 | "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", 413 | "requires": { 414 | "@babel/helper-create-class-features-plugin": "^7.12.1", 415 | "@babel/helper-plugin-utils": "^7.10.4" 416 | } 417 | }, 418 | "@babel/plugin-proposal-unicode-property-regex": { 419 | "version": "7.12.1", 420 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", 421 | "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", 422 | "requires": { 423 | "@babel/helper-create-regexp-features-plugin": "^7.12.1", 424 | "@babel/helper-plugin-utils": "^7.10.4" 425 | } 426 | }, 427 | "@babel/plugin-syntax-async-generators": { 428 | "version": "7.8.4", 429 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", 430 | "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", 431 | "requires": { 432 | "@babel/helper-plugin-utils": "^7.8.0" 433 | } 434 | }, 435 | "@babel/plugin-syntax-class-properties": { 436 | "version": "7.12.1", 437 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", 438 | "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", 439 | "requires": { 440 | "@babel/helper-plugin-utils": "^7.10.4" 441 | } 442 | }, 443 | "@babel/plugin-syntax-dynamic-import": { 444 | "version": "7.8.3", 445 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", 446 | "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", 447 | "requires": { 448 | "@babel/helper-plugin-utils": "^7.8.0" 449 | } 450 | }, 451 | "@babel/plugin-syntax-export-namespace-from": { 452 | "version": "7.8.3", 453 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", 454 | "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", 455 | "requires": { 456 | "@babel/helper-plugin-utils": "^7.8.3" 457 | } 458 | }, 459 | "@babel/plugin-syntax-json-strings": { 460 | "version": "7.8.3", 461 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", 462 | "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", 463 | "requires": { 464 | "@babel/helper-plugin-utils": "^7.8.0" 465 | } 466 | }, 467 | "@babel/plugin-syntax-logical-assignment-operators": { 468 | "version": "7.10.4", 469 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", 470 | "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", 471 | "requires": { 472 | "@babel/helper-plugin-utils": "^7.10.4" 473 | } 474 | }, 475 | "@babel/plugin-syntax-nullish-coalescing-operator": { 476 | "version": "7.8.3", 477 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", 478 | "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", 479 | "requires": { 480 | "@babel/helper-plugin-utils": "^7.8.0" 481 | } 482 | }, 483 | "@babel/plugin-syntax-numeric-separator": { 484 | "version": "7.10.4", 485 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", 486 | "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", 487 | "requires": { 488 | "@babel/helper-plugin-utils": "^7.10.4" 489 | } 490 | }, 491 | "@babel/plugin-syntax-object-rest-spread": { 492 | "version": "7.8.3", 493 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", 494 | "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", 495 | "requires": { 496 | "@babel/helper-plugin-utils": "^7.8.0" 497 | } 498 | }, 499 | "@babel/plugin-syntax-optional-catch-binding": { 500 | "version": "7.8.3", 501 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", 502 | "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", 503 | "requires": { 504 | "@babel/helper-plugin-utils": "^7.8.0" 505 | } 506 | }, 507 | "@babel/plugin-syntax-optional-chaining": { 508 | "version": "7.8.3", 509 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", 510 | "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", 511 | "requires": { 512 | "@babel/helper-plugin-utils": "^7.8.0" 513 | } 514 | }, 515 | "@babel/plugin-syntax-top-level-await": { 516 | "version": "7.12.1", 517 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", 518 | "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", 519 | "requires": { 520 | "@babel/helper-plugin-utils": "^7.10.4" 521 | } 522 | }, 523 | "@babel/plugin-transform-arrow-functions": { 524 | "version": "7.12.1", 525 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", 526 | "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", 527 | "requires": { 528 | "@babel/helper-plugin-utils": "^7.10.4" 529 | } 530 | }, 531 | "@babel/plugin-transform-async-to-generator": { 532 | "version": "7.12.1", 533 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", 534 | "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", 535 | "requires": { 536 | "@babel/helper-module-imports": "^7.12.1", 537 | "@babel/helper-plugin-utils": "^7.10.4", 538 | "@babel/helper-remap-async-to-generator": "^7.12.1" 539 | } 540 | }, 541 | "@babel/plugin-transform-block-scoped-functions": { 542 | "version": "7.12.1", 543 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", 544 | "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", 545 | "requires": { 546 | "@babel/helper-plugin-utils": "^7.10.4" 547 | } 548 | }, 549 | "@babel/plugin-transform-block-scoping": { 550 | "version": "7.12.12", 551 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz", 552 | "integrity": "sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ==", 553 | "requires": { 554 | "@babel/helper-plugin-utils": "^7.10.4" 555 | } 556 | }, 557 | "@babel/plugin-transform-classes": { 558 | "version": "7.12.1", 559 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", 560 | "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", 561 | "requires": { 562 | "@babel/helper-annotate-as-pure": "^7.10.4", 563 | "@babel/helper-define-map": "^7.10.4", 564 | "@babel/helper-function-name": "^7.10.4", 565 | "@babel/helper-optimise-call-expression": "^7.10.4", 566 | "@babel/helper-plugin-utils": "^7.10.4", 567 | "@babel/helper-replace-supers": "^7.12.1", 568 | "@babel/helper-split-export-declaration": "^7.10.4", 569 | "globals": "^11.1.0" 570 | } 571 | }, 572 | "@babel/plugin-transform-computed-properties": { 573 | "version": "7.12.1", 574 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", 575 | "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", 576 | "requires": { 577 | "@babel/helper-plugin-utils": "^7.10.4" 578 | } 579 | }, 580 | "@babel/plugin-transform-destructuring": { 581 | "version": "7.12.1", 582 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", 583 | "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", 584 | "requires": { 585 | "@babel/helper-plugin-utils": "^7.10.4" 586 | } 587 | }, 588 | "@babel/plugin-transform-dotall-regex": { 589 | "version": "7.12.1", 590 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", 591 | "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", 592 | "requires": { 593 | "@babel/helper-create-regexp-features-plugin": "^7.12.1", 594 | "@babel/helper-plugin-utils": "^7.10.4" 595 | } 596 | }, 597 | "@babel/plugin-transform-duplicate-keys": { 598 | "version": "7.12.1", 599 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", 600 | "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", 601 | "requires": { 602 | "@babel/helper-plugin-utils": "^7.10.4" 603 | } 604 | }, 605 | "@babel/plugin-transform-exponentiation-operator": { 606 | "version": "7.12.1", 607 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", 608 | "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", 609 | "requires": { 610 | "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", 611 | "@babel/helper-plugin-utils": "^7.10.4" 612 | } 613 | }, 614 | "@babel/plugin-transform-for-of": { 615 | "version": "7.12.1", 616 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", 617 | "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", 618 | "requires": { 619 | "@babel/helper-plugin-utils": "^7.10.4" 620 | } 621 | }, 622 | "@babel/plugin-transform-function-name": { 623 | "version": "7.12.1", 624 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", 625 | "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", 626 | "requires": { 627 | "@babel/helper-function-name": "^7.10.4", 628 | "@babel/helper-plugin-utils": "^7.10.4" 629 | } 630 | }, 631 | "@babel/plugin-transform-literals": { 632 | "version": "7.12.1", 633 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", 634 | "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", 635 | "requires": { 636 | "@babel/helper-plugin-utils": "^7.10.4" 637 | } 638 | }, 639 | "@babel/plugin-transform-member-expression-literals": { 640 | "version": "7.12.1", 641 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", 642 | "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", 643 | "requires": { 644 | "@babel/helper-plugin-utils": "^7.10.4" 645 | } 646 | }, 647 | "@babel/plugin-transform-modules-amd": { 648 | "version": "7.12.1", 649 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", 650 | "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", 651 | "requires": { 652 | "@babel/helper-module-transforms": "^7.12.1", 653 | "@babel/helper-plugin-utils": "^7.10.4", 654 | "babel-plugin-dynamic-import-node": "^2.3.3" 655 | } 656 | }, 657 | "@babel/plugin-transform-modules-commonjs": { 658 | "version": "7.12.1", 659 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", 660 | "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", 661 | "requires": { 662 | "@babel/helper-module-transforms": "^7.12.1", 663 | "@babel/helper-plugin-utils": "^7.10.4", 664 | "@babel/helper-simple-access": "^7.12.1", 665 | "babel-plugin-dynamic-import-node": "^2.3.3" 666 | } 667 | }, 668 | "@babel/plugin-transform-modules-systemjs": { 669 | "version": "7.12.1", 670 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", 671 | "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", 672 | "requires": { 673 | "@babel/helper-hoist-variables": "^7.10.4", 674 | "@babel/helper-module-transforms": "^7.12.1", 675 | "@babel/helper-plugin-utils": "^7.10.4", 676 | "@babel/helper-validator-identifier": "^7.10.4", 677 | "babel-plugin-dynamic-import-node": "^2.3.3" 678 | } 679 | }, 680 | "@babel/plugin-transform-modules-umd": { 681 | "version": "7.12.1", 682 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", 683 | "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", 684 | "requires": { 685 | "@babel/helper-module-transforms": "^7.12.1", 686 | "@babel/helper-plugin-utils": "^7.10.4" 687 | } 688 | }, 689 | "@babel/plugin-transform-named-capturing-groups-regex": { 690 | "version": "7.12.1", 691 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", 692 | "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", 693 | "requires": { 694 | "@babel/helper-create-regexp-features-plugin": "^7.12.1" 695 | } 696 | }, 697 | "@babel/plugin-transform-new-target": { 698 | "version": "7.12.1", 699 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", 700 | "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", 701 | "requires": { 702 | "@babel/helper-plugin-utils": "^7.10.4" 703 | } 704 | }, 705 | "@babel/plugin-transform-object-super": { 706 | "version": "7.12.1", 707 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", 708 | "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", 709 | "requires": { 710 | "@babel/helper-plugin-utils": "^7.10.4", 711 | "@babel/helper-replace-supers": "^7.12.1" 712 | } 713 | }, 714 | "@babel/plugin-transform-parameters": { 715 | "version": "7.12.1", 716 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", 717 | "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", 718 | "requires": { 719 | "@babel/helper-plugin-utils": "^7.10.4" 720 | } 721 | }, 722 | "@babel/plugin-transform-property-literals": { 723 | "version": "7.12.1", 724 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", 725 | "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", 726 | "requires": { 727 | "@babel/helper-plugin-utils": "^7.10.4" 728 | } 729 | }, 730 | "@babel/plugin-transform-regenerator": { 731 | "version": "7.12.1", 732 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", 733 | "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", 734 | "requires": { 735 | "regenerator-transform": "^0.14.2" 736 | } 737 | }, 738 | "@babel/plugin-transform-reserved-words": { 739 | "version": "7.12.1", 740 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", 741 | "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", 742 | "requires": { 743 | "@babel/helper-plugin-utils": "^7.10.4" 744 | } 745 | }, 746 | "@babel/plugin-transform-shorthand-properties": { 747 | "version": "7.12.1", 748 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", 749 | "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", 750 | "requires": { 751 | "@babel/helper-plugin-utils": "^7.10.4" 752 | } 753 | }, 754 | "@babel/plugin-transform-spread": { 755 | "version": "7.12.1", 756 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", 757 | "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", 758 | "requires": { 759 | "@babel/helper-plugin-utils": "^7.10.4", 760 | "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" 761 | } 762 | }, 763 | "@babel/plugin-transform-sticky-regex": { 764 | "version": "7.12.7", 765 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", 766 | "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", 767 | "requires": { 768 | "@babel/helper-plugin-utils": "^7.10.4" 769 | } 770 | }, 771 | "@babel/plugin-transform-template-literals": { 772 | "version": "7.12.1", 773 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", 774 | "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", 775 | "requires": { 776 | "@babel/helper-plugin-utils": "^7.10.4" 777 | } 778 | }, 779 | "@babel/plugin-transform-typeof-symbol": { 780 | "version": "7.12.10", 781 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz", 782 | "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==", 783 | "requires": { 784 | "@babel/helper-plugin-utils": "^7.10.4" 785 | } 786 | }, 787 | "@babel/plugin-transform-unicode-escapes": { 788 | "version": "7.12.1", 789 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", 790 | "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", 791 | "requires": { 792 | "@babel/helper-plugin-utils": "^7.10.4" 793 | } 794 | }, 795 | "@babel/plugin-transform-unicode-regex": { 796 | "version": "7.12.1", 797 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", 798 | "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", 799 | "requires": { 800 | "@babel/helper-create-regexp-features-plugin": "^7.12.1", 801 | "@babel/helper-plugin-utils": "^7.10.4" 802 | } 803 | }, 804 | "@babel/preset-env": { 805 | "version": "7.12.11", 806 | "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz", 807 | "integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==", 808 | "requires": { 809 | "@babel/compat-data": "^7.12.7", 810 | "@babel/helper-compilation-targets": "^7.12.5", 811 | "@babel/helper-module-imports": "^7.12.5", 812 | "@babel/helper-plugin-utils": "^7.10.4", 813 | "@babel/helper-validator-option": "^7.12.11", 814 | "@babel/plugin-proposal-async-generator-functions": "^7.12.1", 815 | "@babel/plugin-proposal-class-properties": "^7.12.1", 816 | "@babel/plugin-proposal-dynamic-import": "^7.12.1", 817 | "@babel/plugin-proposal-export-namespace-from": "^7.12.1", 818 | "@babel/plugin-proposal-json-strings": "^7.12.1", 819 | "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", 820 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", 821 | "@babel/plugin-proposal-numeric-separator": "^7.12.7", 822 | "@babel/plugin-proposal-object-rest-spread": "^7.12.1", 823 | "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", 824 | "@babel/plugin-proposal-optional-chaining": "^7.12.7", 825 | "@babel/plugin-proposal-private-methods": "^7.12.1", 826 | "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", 827 | "@babel/plugin-syntax-async-generators": "^7.8.0", 828 | "@babel/plugin-syntax-class-properties": "^7.12.1", 829 | "@babel/plugin-syntax-dynamic-import": "^7.8.0", 830 | "@babel/plugin-syntax-export-namespace-from": "^7.8.3", 831 | "@babel/plugin-syntax-json-strings": "^7.8.0", 832 | "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", 833 | "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", 834 | "@babel/plugin-syntax-numeric-separator": "^7.10.4", 835 | "@babel/plugin-syntax-object-rest-spread": "^7.8.0", 836 | "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", 837 | "@babel/plugin-syntax-optional-chaining": "^7.8.0", 838 | "@babel/plugin-syntax-top-level-await": "^7.12.1", 839 | "@babel/plugin-transform-arrow-functions": "^7.12.1", 840 | "@babel/plugin-transform-async-to-generator": "^7.12.1", 841 | "@babel/plugin-transform-block-scoped-functions": "^7.12.1", 842 | "@babel/plugin-transform-block-scoping": "^7.12.11", 843 | "@babel/plugin-transform-classes": "^7.12.1", 844 | "@babel/plugin-transform-computed-properties": "^7.12.1", 845 | "@babel/plugin-transform-destructuring": "^7.12.1", 846 | "@babel/plugin-transform-dotall-regex": "^7.12.1", 847 | "@babel/plugin-transform-duplicate-keys": "^7.12.1", 848 | "@babel/plugin-transform-exponentiation-operator": "^7.12.1", 849 | "@babel/plugin-transform-for-of": "^7.12.1", 850 | "@babel/plugin-transform-function-name": "^7.12.1", 851 | "@babel/plugin-transform-literals": "^7.12.1", 852 | "@babel/plugin-transform-member-expression-literals": "^7.12.1", 853 | "@babel/plugin-transform-modules-amd": "^7.12.1", 854 | "@babel/plugin-transform-modules-commonjs": "^7.12.1", 855 | "@babel/plugin-transform-modules-systemjs": "^7.12.1", 856 | "@babel/plugin-transform-modules-umd": "^7.12.1", 857 | "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", 858 | "@babel/plugin-transform-new-target": "^7.12.1", 859 | "@babel/plugin-transform-object-super": "^7.12.1", 860 | "@babel/plugin-transform-parameters": "^7.12.1", 861 | "@babel/plugin-transform-property-literals": "^7.12.1", 862 | "@babel/plugin-transform-regenerator": "^7.12.1", 863 | "@babel/plugin-transform-reserved-words": "^7.12.1", 864 | "@babel/plugin-transform-shorthand-properties": "^7.12.1", 865 | "@babel/plugin-transform-spread": "^7.12.1", 866 | "@babel/plugin-transform-sticky-regex": "^7.12.7", 867 | "@babel/plugin-transform-template-literals": "^7.12.1", 868 | "@babel/plugin-transform-typeof-symbol": "^7.12.10", 869 | "@babel/plugin-transform-unicode-escapes": "^7.12.1", 870 | "@babel/plugin-transform-unicode-regex": "^7.12.1", 871 | "@babel/preset-modules": "^0.1.3", 872 | "@babel/types": "^7.12.11", 873 | "core-js-compat": "^3.8.0", 874 | "semver": "^5.5.0" 875 | }, 876 | "dependencies": { 877 | "semver": { 878 | "version": "5.7.1", 879 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 880 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 881 | } 882 | } 883 | }, 884 | "@babel/preset-modules": { 885 | "version": "0.1.4", 886 | "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", 887 | "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", 888 | "requires": { 889 | "@babel/helper-plugin-utils": "^7.0.0", 890 | "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", 891 | "@babel/plugin-transform-dotall-regex": "^7.4.4", 892 | "@babel/types": "^7.4.4", 893 | "esutils": "^2.0.2" 894 | } 895 | }, 896 | "@babel/runtime": { 897 | "version": "7.12.5", 898 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", 899 | "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", 900 | "requires": { 901 | "regenerator-runtime": "^0.13.4" 902 | } 903 | }, 904 | "@babel/template": { 905 | "version": "7.12.7", 906 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", 907 | "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", 908 | "requires": { 909 | "@babel/code-frame": "^7.10.4", 910 | "@babel/parser": "^7.12.7", 911 | "@babel/types": "^7.12.7" 912 | } 913 | }, 914 | "@babel/traverse": { 915 | "version": "7.12.12", 916 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", 917 | "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", 918 | "requires": { 919 | "@babel/code-frame": "^7.12.11", 920 | "@babel/generator": "^7.12.11", 921 | "@babel/helper-function-name": "^7.12.11", 922 | "@babel/helper-split-export-declaration": "^7.12.11", 923 | "@babel/parser": "^7.12.11", 924 | "@babel/types": "^7.12.12", 925 | "debug": "^4.1.0", 926 | "globals": "^11.1.0", 927 | "lodash": "^4.17.19" 928 | } 929 | }, 930 | "@babel/types": { 931 | "version": "7.12.12", 932 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", 933 | "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", 934 | "requires": { 935 | "@babel/helper-validator-identifier": "^7.12.11", 936 | "lodash": "^4.17.19", 937 | "to-fast-properties": "^2.0.0" 938 | } 939 | }, 940 | "@discoveryjs/json-ext": { 941 | "version": "0.5.2", 942 | "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz", 943 | "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", 944 | "dev": true 945 | }, 946 | "@hotwired/turbo": { 947 | "version": "7.0.0-beta.1", 948 | "resolved": "https://registry.npmjs.org/@hotwired/turbo/-/turbo-7.0.0-beta.1.tgz", 949 | "integrity": "sha512-V7hhELbDkYUGaHw/Yw4tu9pDUT1WE4t3A7tRs7Zh0Uwtk2vaJnmykNZ2uq20BnLjofufA1+MLJZ6AXJ3B/Il5A==" 950 | }, 951 | "@nodelib/fs.scandir": { 952 | "version": "2.1.4", 953 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", 954 | "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", 955 | "dev": true, 956 | "requires": { 957 | "@nodelib/fs.stat": "2.0.4", 958 | "run-parallel": "^1.1.9" 959 | } 960 | }, 961 | "@nodelib/fs.stat": { 962 | "version": "2.0.4", 963 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", 964 | "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", 965 | "dev": true 966 | }, 967 | "@nodelib/fs.walk": { 968 | "version": "1.2.6", 969 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", 970 | "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", 971 | "dev": true, 972 | "requires": { 973 | "@nodelib/fs.scandir": "2.1.4", 974 | "fastq": "^1.6.0" 975 | } 976 | }, 977 | "@types/eslint": { 978 | "version": "7.2.6", 979 | "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", 980 | "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==", 981 | "dev": true, 982 | "requires": { 983 | "@types/estree": "*", 984 | "@types/json-schema": "*" 985 | } 986 | }, 987 | "@types/eslint-scope": { 988 | "version": "3.7.0", 989 | "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", 990 | "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", 991 | "dev": true, 992 | "requires": { 993 | "@types/eslint": "*", 994 | "@types/estree": "*" 995 | } 996 | }, 997 | "@types/estree": { 998 | "version": "0.0.45", 999 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", 1000 | "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", 1001 | "dev": true 1002 | }, 1003 | "@types/json-schema": { 1004 | "version": "7.0.6", 1005 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", 1006 | "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==" 1007 | }, 1008 | "@types/node": { 1009 | "version": "14.14.16", 1010 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.16.tgz", 1011 | "integrity": "sha512-naXYePhweTi+BMv11TgioE2/FXU4fSl29HAH1ffxVciNsH3rYXjNP2yM8wqmSm7jS20gM8TIklKiTen+1iVncw==", 1012 | "dev": true 1013 | }, 1014 | "@webassemblyjs/ast": { 1015 | "version": "1.9.1", 1016 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.1.tgz", 1017 | "integrity": "sha512-uMu1nCWn2Wxyy126LlGqRVlhdTOsO/bsBRI4dNq3+6SiSuRKRQX6ejjKgh82LoGAPSq72lDUiQ4FWVaf0PecYw==", 1018 | "dev": true, 1019 | "requires": { 1020 | "@webassemblyjs/helper-module-context": "1.9.1", 1021 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 1022 | "@webassemblyjs/wast-parser": "1.9.1" 1023 | } 1024 | }, 1025 | "@webassemblyjs/floating-point-hex-parser": { 1026 | "version": "1.9.1", 1027 | "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.1.tgz", 1028 | "integrity": "sha512-5VEKu024RySmLKTTBl9q1eO/2K5jk9ZS+2HXDBLA9s9p5IjkaXxWiDb/+b7wSQp6FRdLaH1IVGIfOex58Na2pg==", 1029 | "dev": true 1030 | }, 1031 | "@webassemblyjs/helper-api-error": { 1032 | "version": "1.9.1", 1033 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.1.tgz", 1034 | "integrity": "sha512-y1lGmfm38djrScwpeL37rRR9f1D6sM8RhMpvM7CYLzOlHVboouZokXK/G88BpzW0NQBSvCCOnW5BFhten4FPfA==", 1035 | "dev": true 1036 | }, 1037 | "@webassemblyjs/helper-buffer": { 1038 | "version": "1.9.1", 1039 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.1.tgz", 1040 | "integrity": "sha512-uS6VSgieHbk/m4GSkMU5cqe/5TekdCzQso4revCIEQ3vpGZgqSSExi4jWpTWwDpAHOIAb1Jfrs0gUB9AA4n71w==", 1041 | "dev": true 1042 | }, 1043 | "@webassemblyjs/helper-code-frame": { 1044 | "version": "1.9.1", 1045 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.1.tgz", 1046 | "integrity": "sha512-ZQ2ZT6Evk4DPIfD+92AraGYaFIqGm4U20e7FpXwl7WUo2Pn1mZ1v8VGH8i+Y++IQpxPbQo/UyG0Khs7eInskzA==", 1047 | "dev": true, 1048 | "requires": { 1049 | "@webassemblyjs/wast-printer": "1.9.1" 1050 | } 1051 | }, 1052 | "@webassemblyjs/helper-fsm": { 1053 | "version": "1.9.1", 1054 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.1.tgz", 1055 | "integrity": "sha512-J32HGpveEqqcKFS0YbgicB0zAlpfIxJa5MjxDxhu3i5ltPcVfY5EPvKQ1suRguFPehxiUs+/hfkwPEXom/l0lw==", 1056 | "dev": true 1057 | }, 1058 | "@webassemblyjs/helper-module-context": { 1059 | "version": "1.9.1", 1060 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.1.tgz", 1061 | "integrity": "sha512-IEH2cMmEQKt7fqelLWB5e/cMdZXf2rST1JIrzWmf4XBt3QTxGdnnLvV4DYoN8pJjOx0VYXsWg+yF16MmJtolZg==", 1062 | "dev": true, 1063 | "requires": { 1064 | "@webassemblyjs/ast": "1.9.1" 1065 | } 1066 | }, 1067 | "@webassemblyjs/helper-wasm-bytecode": { 1068 | "version": "1.9.1", 1069 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.1.tgz", 1070 | "integrity": "sha512-i2rGTBqFUcSXxyjt2K4vm/3kkHwyzG6o427iCjcIKjOqpWH8SEem+xe82jUk1iydJO250/CvE5o7hzNAMZf0dQ==", 1071 | "dev": true 1072 | }, 1073 | "@webassemblyjs/helper-wasm-section": { 1074 | "version": "1.9.1", 1075 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.1.tgz", 1076 | "integrity": "sha512-FetqzjtXZr2d57IECK+aId3D0IcGweeM0CbAnJHkYJkcRTHP+YcMb7Wmc0j21h5UWBpwYGb9dSkK/93SRCTrGg==", 1077 | "dev": true, 1078 | "requires": { 1079 | "@webassemblyjs/ast": "1.9.1", 1080 | "@webassemblyjs/helper-buffer": "1.9.1", 1081 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 1082 | "@webassemblyjs/wasm-gen": "1.9.1" 1083 | } 1084 | }, 1085 | "@webassemblyjs/ieee754": { 1086 | "version": "1.9.1", 1087 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.1.tgz", 1088 | "integrity": "sha512-EvTG9M78zP1MmkBpUjGQHZc26DzPGZSLIPxYHCjQsBMo60Qy2W34qf8z0exRDtxBbRIoiKa5dFyWer/7r1aaSQ==", 1089 | "dev": true, 1090 | "requires": { 1091 | "@xtuc/ieee754": "^1.2.0" 1092 | } 1093 | }, 1094 | "@webassemblyjs/leb128": { 1095 | "version": "1.9.1", 1096 | "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.1.tgz", 1097 | "integrity": "sha512-Oc04ub0vFfLnF+2/+ki3AE+anmW4sv9uNBqb+79fgTaPv6xJsOT0dhphNfL3FrME84CbX/D1T9XT8tjFo0IIiw==", 1098 | "dev": true, 1099 | "requires": { 1100 | "@xtuc/long": "4.2.2" 1101 | } 1102 | }, 1103 | "@webassemblyjs/utf8": { 1104 | "version": "1.9.1", 1105 | "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.1.tgz", 1106 | "integrity": "sha512-llkYtppagjCodFjo0alWOUhAkfOiQPQDIc5oA6C9sFAXz7vC9QhZf/f8ijQIX+A9ToM3c9Pq85X0EX7nx9gVhg==", 1107 | "dev": true 1108 | }, 1109 | "@webassemblyjs/wasm-edit": { 1110 | "version": "1.9.1", 1111 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.1.tgz", 1112 | "integrity": "sha512-S2IaD6+x9B2Xi8BCT0eGsrXXd8UxAh2LVJpg1ZMtHXnrDcsTtIX2bDjHi40Hio6Lc62dWHmKdvksI+MClCYbbw==", 1113 | "dev": true, 1114 | "requires": { 1115 | "@webassemblyjs/ast": "1.9.1", 1116 | "@webassemblyjs/helper-buffer": "1.9.1", 1117 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 1118 | "@webassemblyjs/helper-wasm-section": "1.9.1", 1119 | "@webassemblyjs/wasm-gen": "1.9.1", 1120 | "@webassemblyjs/wasm-opt": "1.9.1", 1121 | "@webassemblyjs/wasm-parser": "1.9.1", 1122 | "@webassemblyjs/wast-printer": "1.9.1" 1123 | } 1124 | }, 1125 | "@webassemblyjs/wasm-gen": { 1126 | "version": "1.9.1", 1127 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.1.tgz", 1128 | "integrity": "sha512-bqWI0S4lBQsEN5FTZ35vYzfKUJvtjNnBobB1agCALH30xNk1LToZ7Z8eiaR/Z5iVECTlBndoRQV3F6mbEqE/fg==", 1129 | "dev": true, 1130 | "requires": { 1131 | "@webassemblyjs/ast": "1.9.1", 1132 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 1133 | "@webassemblyjs/ieee754": "1.9.1", 1134 | "@webassemblyjs/leb128": "1.9.1", 1135 | "@webassemblyjs/utf8": "1.9.1" 1136 | } 1137 | }, 1138 | "@webassemblyjs/wasm-opt": { 1139 | "version": "1.9.1", 1140 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.1.tgz", 1141 | "integrity": "sha512-gSf7I7YWVXZ5c6XqTEqkZjVs8K1kc1k57vsB6KBQscSagDNbAdxt6MwuJoMjsE1yWY1tsuL+pga268A6u+Fdkg==", 1142 | "dev": true, 1143 | "requires": { 1144 | "@webassemblyjs/ast": "1.9.1", 1145 | "@webassemblyjs/helper-buffer": "1.9.1", 1146 | "@webassemblyjs/wasm-gen": "1.9.1", 1147 | "@webassemblyjs/wasm-parser": "1.9.1" 1148 | } 1149 | }, 1150 | "@webassemblyjs/wasm-parser": { 1151 | "version": "1.9.1", 1152 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.1.tgz", 1153 | "integrity": "sha512-ImM4N2T1MEIond0MyE3rXvStVxEmivQrDKf/ggfh5pP6EHu3lL/YTAoSrR7shrbKNPpeKpGesW1LIK/L4kqduw==", 1154 | "dev": true, 1155 | "requires": { 1156 | "@webassemblyjs/ast": "1.9.1", 1157 | "@webassemblyjs/helper-api-error": "1.9.1", 1158 | "@webassemblyjs/helper-wasm-bytecode": "1.9.1", 1159 | "@webassemblyjs/ieee754": "1.9.1", 1160 | "@webassemblyjs/leb128": "1.9.1", 1161 | "@webassemblyjs/utf8": "1.9.1" 1162 | } 1163 | }, 1164 | "@webassemblyjs/wast-parser": { 1165 | "version": "1.9.1", 1166 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.1.tgz", 1167 | "integrity": "sha512-2xVxejXSvj3ls/o2TR/zI6p28qsGupjHhnHL6URULQRcXmryn3w7G83jQMcT7PHqUfyle65fZtWLukfdLdE7qw==", 1168 | "dev": true, 1169 | "requires": { 1170 | "@webassemblyjs/ast": "1.9.1", 1171 | "@webassemblyjs/floating-point-hex-parser": "1.9.1", 1172 | "@webassemblyjs/helper-api-error": "1.9.1", 1173 | "@webassemblyjs/helper-code-frame": "1.9.1", 1174 | "@webassemblyjs/helper-fsm": "1.9.1", 1175 | "@xtuc/long": "4.2.2" 1176 | } 1177 | }, 1178 | "@webassemblyjs/wast-printer": { 1179 | "version": "1.9.1", 1180 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.1.tgz", 1181 | "integrity": "sha512-tDV8V15wm7mmbAH6XvQRU1X+oPGmeOzYsd6h7hlRLz6QpV4Ec/KKxM8OpLtFmQPLCreGxTp+HuxtH4pRIZyL9w==", 1182 | "dev": true, 1183 | "requires": { 1184 | "@webassemblyjs/ast": "1.9.1", 1185 | "@webassemblyjs/wast-parser": "1.9.1", 1186 | "@xtuc/long": "4.2.2" 1187 | } 1188 | }, 1189 | "@webpack-cli/info": { 1190 | "version": "1.2.0", 1191 | "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.0.tgz", 1192 | "integrity": "sha512-+wA8lBKopgKmN76BSGJVJby5ZXDlsrO6p/nm7fUBsHznRNWB/ozotJP7Yfcz8JPfqeG2LxwYlTH2u6D9a/0XAw==", 1193 | "dev": true, 1194 | "requires": { 1195 | "envinfo": "^7.7.3" 1196 | } 1197 | }, 1198 | "@webpack-cli/serve": { 1199 | "version": "1.2.0", 1200 | "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.0.tgz", 1201 | "integrity": "sha512-jI3P7jMp/AXDSPkM+ClwRcJZbxnlvNC8bVZBmyRr4scMMZ4p5WQcXkw3Q+Hc7RQekomJlBMN+UQGliT4hhG8Vw==", 1202 | "dev": true 1203 | }, 1204 | "@xtuc/ieee754": { 1205 | "version": "1.2.0", 1206 | "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", 1207 | "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", 1208 | "dev": true 1209 | }, 1210 | "@xtuc/long": { 1211 | "version": "4.2.2", 1212 | "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", 1213 | "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", 1214 | "dev": true 1215 | }, 1216 | "acorn": { 1217 | "version": "8.0.4", 1218 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz", 1219 | "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==", 1220 | "dev": true 1221 | }, 1222 | "ajv": { 1223 | "version": "6.12.6", 1224 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 1225 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 1226 | "requires": { 1227 | "fast-deep-equal": "^3.1.1", 1228 | "fast-json-stable-stringify": "^2.0.0", 1229 | "json-schema-traverse": "^0.4.1", 1230 | "uri-js": "^4.2.2" 1231 | } 1232 | }, 1233 | "ajv-keywords": { 1234 | "version": "3.5.2", 1235 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", 1236 | "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" 1237 | }, 1238 | "ansi-colors": { 1239 | "version": "4.1.1", 1240 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 1241 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 1242 | "dev": true 1243 | }, 1244 | "ansi-styles": { 1245 | "version": "3.2.1", 1246 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 1247 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 1248 | "requires": { 1249 | "color-convert": "^1.9.0" 1250 | } 1251 | }, 1252 | "array-union": { 1253 | "version": "2.1.0", 1254 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 1255 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 1256 | "dev": true 1257 | }, 1258 | "babel-loader": { 1259 | "version": "8.2.2", 1260 | "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz", 1261 | "integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==", 1262 | "requires": { 1263 | "find-cache-dir": "^3.3.1", 1264 | "loader-utils": "^1.4.0", 1265 | "make-dir": "^3.1.0", 1266 | "schema-utils": "^2.6.5" 1267 | }, 1268 | "dependencies": { 1269 | "json5": { 1270 | "version": "1.0.1", 1271 | "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", 1272 | "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", 1273 | "requires": { 1274 | "minimist": "^1.2.0" 1275 | } 1276 | }, 1277 | "loader-utils": { 1278 | "version": "1.4.0", 1279 | "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", 1280 | "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", 1281 | "requires": { 1282 | "big.js": "^5.2.2", 1283 | "emojis-list": "^3.0.0", 1284 | "json5": "^1.0.1" 1285 | } 1286 | }, 1287 | "schema-utils": { 1288 | "version": "2.7.1", 1289 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", 1290 | "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", 1291 | "requires": { 1292 | "@types/json-schema": "^7.0.5", 1293 | "ajv": "^6.12.4", 1294 | "ajv-keywords": "^3.5.2" 1295 | } 1296 | } 1297 | } 1298 | }, 1299 | "babel-plugin-dynamic-import-node": { 1300 | "version": "2.3.3", 1301 | "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", 1302 | "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", 1303 | "requires": { 1304 | "object.assign": "^4.1.0" 1305 | } 1306 | }, 1307 | "big.js": { 1308 | "version": "5.2.2", 1309 | "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", 1310 | "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" 1311 | }, 1312 | "braces": { 1313 | "version": "3.0.2", 1314 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1315 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1316 | "dev": true, 1317 | "requires": { 1318 | "fill-range": "^7.0.1" 1319 | } 1320 | }, 1321 | "browserslist": { 1322 | "version": "4.16.0", 1323 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz", 1324 | "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==", 1325 | "requires": { 1326 | "caniuse-lite": "^1.0.30001165", 1327 | "colorette": "^1.2.1", 1328 | "electron-to-chromium": "^1.3.621", 1329 | "escalade": "^3.1.1", 1330 | "node-releases": "^1.1.67" 1331 | } 1332 | }, 1333 | "buffer-from": { 1334 | "version": "1.1.1", 1335 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 1336 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 1337 | "dev": true 1338 | }, 1339 | "call-bind": { 1340 | "version": "1.0.0", 1341 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", 1342 | "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", 1343 | "requires": { 1344 | "function-bind": "^1.1.1", 1345 | "get-intrinsic": "^1.0.0" 1346 | } 1347 | }, 1348 | "caniuse-lite": { 1349 | "version": "1.0.30001171", 1350 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001171.tgz", 1351 | "integrity": "sha512-5Alrh8TTYPG9IH4UkRqEBZoEToWRLvPbSQokvzSz0lii8/FOWKG4keO1HoYfPWs8IF/NH/dyNPg1cmJGvV3Zlg==" 1352 | }, 1353 | "chalk": { 1354 | "version": "2.4.2", 1355 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 1356 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 1357 | "requires": { 1358 | "ansi-styles": "^3.2.1", 1359 | "escape-string-regexp": "^1.0.5", 1360 | "supports-color": "^5.3.0" 1361 | }, 1362 | "dependencies": { 1363 | "has-flag": { 1364 | "version": "3.0.0", 1365 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1366 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 1367 | }, 1368 | "supports-color": { 1369 | "version": "5.5.0", 1370 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1371 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1372 | "requires": { 1373 | "has-flag": "^3.0.0" 1374 | } 1375 | } 1376 | } 1377 | }, 1378 | "chrome-trace-event": { 1379 | "version": "1.0.2", 1380 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", 1381 | "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", 1382 | "dev": true, 1383 | "requires": { 1384 | "tslib": "^1.9.0" 1385 | } 1386 | }, 1387 | "color-convert": { 1388 | "version": "1.9.3", 1389 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 1390 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 1391 | "requires": { 1392 | "color-name": "1.1.3" 1393 | } 1394 | }, 1395 | "color-name": { 1396 | "version": "1.1.3", 1397 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 1398 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 1399 | }, 1400 | "colorette": { 1401 | "version": "1.2.1", 1402 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", 1403 | "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==" 1404 | }, 1405 | "commander": { 1406 | "version": "2.20.3", 1407 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 1408 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 1409 | "dev": true 1410 | }, 1411 | "commondir": { 1412 | "version": "1.0.1", 1413 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", 1414 | "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" 1415 | }, 1416 | "convert-source-map": { 1417 | "version": "1.7.0", 1418 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", 1419 | "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", 1420 | "requires": { 1421 | "safe-buffer": "~5.1.1" 1422 | }, 1423 | "dependencies": { 1424 | "safe-buffer": { 1425 | "version": "5.1.2", 1426 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1427 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1428 | } 1429 | } 1430 | }, 1431 | "copy-webpack-plugin": { 1432 | "version": "7.0.0", 1433 | "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-7.0.0.tgz", 1434 | "integrity": "sha512-SLjQNa5iE3BoCP76ESU9qYo9ZkEWtXoZxDurHoqPchAFRblJ9g96xTeC560UXBMre1Nx6ixIIUfiY3VcjpJw3g==", 1435 | "dev": true, 1436 | "requires": { 1437 | "fast-glob": "^3.2.4", 1438 | "glob-parent": "^5.1.1", 1439 | "globby": "^11.0.1", 1440 | "loader-utils": "^2.0.0", 1441 | "normalize-path": "^3.0.0", 1442 | "p-limit": "^3.0.2", 1443 | "schema-utils": "^3.0.0", 1444 | "serialize-javascript": "^5.0.1" 1445 | } 1446 | }, 1447 | "core-js-compat": { 1448 | "version": "3.8.1", 1449 | "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.1.tgz", 1450 | "integrity": "sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==", 1451 | "requires": { 1452 | "browserslist": "^4.15.0", 1453 | "semver": "7.0.0" 1454 | }, 1455 | "dependencies": { 1456 | "semver": { 1457 | "version": "7.0.0", 1458 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", 1459 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" 1460 | } 1461 | } 1462 | }, 1463 | "cross-spawn": { 1464 | "version": "7.0.3", 1465 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 1466 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 1467 | "dev": true, 1468 | "requires": { 1469 | "path-key": "^3.1.0", 1470 | "shebang-command": "^2.0.0", 1471 | "which": "^2.0.1" 1472 | } 1473 | }, 1474 | "debug": { 1475 | "version": "4.3.1", 1476 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 1477 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 1478 | "requires": { 1479 | "ms": "2.1.2" 1480 | } 1481 | }, 1482 | "define-properties": { 1483 | "version": "1.1.3", 1484 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 1485 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 1486 | "requires": { 1487 | "object-keys": "^1.0.12" 1488 | } 1489 | }, 1490 | "dir-glob": { 1491 | "version": "3.0.1", 1492 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 1493 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 1494 | "dev": true, 1495 | "requires": { 1496 | "path-type": "^4.0.0" 1497 | } 1498 | }, 1499 | "electron-to-chromium": { 1500 | "version": "1.3.633", 1501 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.633.tgz", 1502 | "integrity": "sha512-bsVCsONiVX1abkWdH7KtpuDAhsQ3N3bjPYhROSAXE78roJKet0Y5wznA14JE9pzbwSZmSMAW6KiKYf1RvbTJkA==" 1503 | }, 1504 | "emojis-list": { 1505 | "version": "3.0.0", 1506 | "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", 1507 | "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" 1508 | }, 1509 | "end-of-stream": { 1510 | "version": "1.4.4", 1511 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 1512 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 1513 | "dev": true, 1514 | "requires": { 1515 | "once": "^1.4.0" 1516 | } 1517 | }, 1518 | "enhanced-resolve": { 1519 | "version": "5.4.1", 1520 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz", 1521 | "integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==", 1522 | "dev": true, 1523 | "requires": { 1524 | "graceful-fs": "^4.2.4", 1525 | "tapable": "^2.2.0" 1526 | } 1527 | }, 1528 | "enquirer": { 1529 | "version": "2.3.6", 1530 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", 1531 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", 1532 | "dev": true, 1533 | "requires": { 1534 | "ansi-colors": "^4.1.1" 1535 | } 1536 | }, 1537 | "envinfo": { 1538 | "version": "7.7.3", 1539 | "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.3.tgz", 1540 | "integrity": "sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA==", 1541 | "dev": true 1542 | }, 1543 | "escalade": { 1544 | "version": "3.1.1", 1545 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1546 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" 1547 | }, 1548 | "escape-string-regexp": { 1549 | "version": "1.0.5", 1550 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 1551 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 1552 | }, 1553 | "eslint-scope": { 1554 | "version": "5.1.1", 1555 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 1556 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 1557 | "dev": true, 1558 | "requires": { 1559 | "esrecurse": "^4.3.0", 1560 | "estraverse": "^4.1.1" 1561 | } 1562 | }, 1563 | "esrecurse": { 1564 | "version": "4.3.0", 1565 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1566 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1567 | "dev": true, 1568 | "requires": { 1569 | "estraverse": "^5.2.0" 1570 | }, 1571 | "dependencies": { 1572 | "estraverse": { 1573 | "version": "5.2.0", 1574 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 1575 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 1576 | "dev": true 1577 | } 1578 | } 1579 | }, 1580 | "estraverse": { 1581 | "version": "4.3.0", 1582 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 1583 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 1584 | "dev": true 1585 | }, 1586 | "esutils": { 1587 | "version": "2.0.3", 1588 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 1589 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" 1590 | }, 1591 | "events": { 1592 | "version": "3.2.0", 1593 | "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", 1594 | "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", 1595 | "dev": true 1596 | }, 1597 | "execa": { 1598 | "version": "4.1.0", 1599 | "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", 1600 | "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", 1601 | "dev": true, 1602 | "requires": { 1603 | "cross-spawn": "^7.0.0", 1604 | "get-stream": "^5.0.0", 1605 | "human-signals": "^1.1.1", 1606 | "is-stream": "^2.0.0", 1607 | "merge-stream": "^2.0.0", 1608 | "npm-run-path": "^4.0.0", 1609 | "onetime": "^5.1.0", 1610 | "signal-exit": "^3.0.2", 1611 | "strip-final-newline": "^2.0.0" 1612 | } 1613 | }, 1614 | "fast-deep-equal": { 1615 | "version": "3.1.3", 1616 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1617 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 1618 | }, 1619 | "fast-glob": { 1620 | "version": "3.2.4", 1621 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", 1622 | "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", 1623 | "dev": true, 1624 | "requires": { 1625 | "@nodelib/fs.stat": "^2.0.2", 1626 | "@nodelib/fs.walk": "^1.2.3", 1627 | "glob-parent": "^5.1.0", 1628 | "merge2": "^1.3.0", 1629 | "micromatch": "^4.0.2", 1630 | "picomatch": "^2.2.1" 1631 | } 1632 | }, 1633 | "fast-json-stable-stringify": { 1634 | "version": "2.1.0", 1635 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1636 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 1637 | }, 1638 | "fastest-levenshtein": { 1639 | "version": "1.0.12", 1640 | "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", 1641 | "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", 1642 | "dev": true 1643 | }, 1644 | "fastq": { 1645 | "version": "1.10.0", 1646 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz", 1647 | "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==", 1648 | "dev": true, 1649 | "requires": { 1650 | "reusify": "^1.0.4" 1651 | } 1652 | }, 1653 | "fill-range": { 1654 | "version": "7.0.1", 1655 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1656 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1657 | "dev": true, 1658 | "requires": { 1659 | "to-regex-range": "^5.0.1" 1660 | } 1661 | }, 1662 | "find-cache-dir": { 1663 | "version": "3.3.1", 1664 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", 1665 | "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", 1666 | "requires": { 1667 | "commondir": "^1.0.1", 1668 | "make-dir": "^3.0.2", 1669 | "pkg-dir": "^4.1.0" 1670 | }, 1671 | "dependencies": { 1672 | "find-up": { 1673 | "version": "4.1.0", 1674 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 1675 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 1676 | "requires": { 1677 | "locate-path": "^5.0.0", 1678 | "path-exists": "^4.0.0" 1679 | } 1680 | }, 1681 | "locate-path": { 1682 | "version": "5.0.0", 1683 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 1684 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 1685 | "requires": { 1686 | "p-locate": "^4.1.0" 1687 | } 1688 | }, 1689 | "p-limit": { 1690 | "version": "2.3.0", 1691 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 1692 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 1693 | "requires": { 1694 | "p-try": "^2.0.0" 1695 | } 1696 | }, 1697 | "p-locate": { 1698 | "version": "4.1.0", 1699 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 1700 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 1701 | "requires": { 1702 | "p-limit": "^2.2.0" 1703 | } 1704 | }, 1705 | "pkg-dir": { 1706 | "version": "4.2.0", 1707 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 1708 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 1709 | "requires": { 1710 | "find-up": "^4.0.0" 1711 | } 1712 | } 1713 | } 1714 | }, 1715 | "find-up": { 1716 | "version": "5.0.0", 1717 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1718 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1719 | "dev": true, 1720 | "requires": { 1721 | "locate-path": "^6.0.0", 1722 | "path-exists": "^4.0.0" 1723 | } 1724 | }, 1725 | "function-bind": { 1726 | "version": "1.1.1", 1727 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1728 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 1729 | }, 1730 | "gensync": { 1731 | "version": "1.0.0-beta.2", 1732 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 1733 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" 1734 | }, 1735 | "get-intrinsic": { 1736 | "version": "1.0.2", 1737 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", 1738 | "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", 1739 | "requires": { 1740 | "function-bind": "^1.1.1", 1741 | "has": "^1.0.3", 1742 | "has-symbols": "^1.0.1" 1743 | } 1744 | }, 1745 | "get-stream": { 1746 | "version": "5.2.0", 1747 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 1748 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 1749 | "dev": true, 1750 | "requires": { 1751 | "pump": "^3.0.0" 1752 | } 1753 | }, 1754 | "glob-parent": { 1755 | "version": "5.1.1", 1756 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 1757 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 1758 | "dev": true, 1759 | "requires": { 1760 | "is-glob": "^4.0.1" 1761 | } 1762 | }, 1763 | "glob-to-regexp": { 1764 | "version": "0.4.1", 1765 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", 1766 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", 1767 | "dev": true 1768 | }, 1769 | "globals": { 1770 | "version": "11.12.0", 1771 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 1772 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" 1773 | }, 1774 | "globby": { 1775 | "version": "11.0.1", 1776 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", 1777 | "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", 1778 | "dev": true, 1779 | "requires": { 1780 | "array-union": "^2.1.0", 1781 | "dir-glob": "^3.0.1", 1782 | "fast-glob": "^3.1.1", 1783 | "ignore": "^5.1.4", 1784 | "merge2": "^1.3.0", 1785 | "slash": "^3.0.0" 1786 | } 1787 | }, 1788 | "graceful-fs": { 1789 | "version": "4.2.4", 1790 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", 1791 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", 1792 | "dev": true 1793 | }, 1794 | "has": { 1795 | "version": "1.0.3", 1796 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1797 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1798 | "requires": { 1799 | "function-bind": "^1.1.1" 1800 | } 1801 | }, 1802 | "has-flag": { 1803 | "version": "4.0.0", 1804 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1805 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1806 | "dev": true 1807 | }, 1808 | "has-symbols": { 1809 | "version": "1.0.1", 1810 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 1811 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" 1812 | }, 1813 | "human-signals": { 1814 | "version": "1.1.1", 1815 | "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", 1816 | "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", 1817 | "dev": true 1818 | }, 1819 | "ignore": { 1820 | "version": "5.1.8", 1821 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", 1822 | "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", 1823 | "dev": true 1824 | }, 1825 | "import-local": { 1826 | "version": "3.0.2", 1827 | "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", 1828 | "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", 1829 | "dev": true, 1830 | "requires": { 1831 | "pkg-dir": "^4.2.0", 1832 | "resolve-cwd": "^3.0.0" 1833 | }, 1834 | "dependencies": { 1835 | "find-up": { 1836 | "version": "4.1.0", 1837 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 1838 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 1839 | "dev": true, 1840 | "requires": { 1841 | "locate-path": "^5.0.0", 1842 | "path-exists": "^4.0.0" 1843 | } 1844 | }, 1845 | "locate-path": { 1846 | "version": "5.0.0", 1847 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 1848 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 1849 | "dev": true, 1850 | "requires": { 1851 | "p-locate": "^4.1.0" 1852 | } 1853 | }, 1854 | "p-limit": { 1855 | "version": "2.3.0", 1856 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 1857 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 1858 | "dev": true, 1859 | "requires": { 1860 | "p-try": "^2.0.0" 1861 | } 1862 | }, 1863 | "p-locate": { 1864 | "version": "4.1.0", 1865 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 1866 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 1867 | "dev": true, 1868 | "requires": { 1869 | "p-limit": "^2.2.0" 1870 | } 1871 | }, 1872 | "pkg-dir": { 1873 | "version": "4.2.0", 1874 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 1875 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 1876 | "dev": true, 1877 | "requires": { 1878 | "find-up": "^4.0.0" 1879 | } 1880 | } 1881 | } 1882 | }, 1883 | "interpret": { 1884 | "version": "2.2.0", 1885 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", 1886 | "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", 1887 | "dev": true 1888 | }, 1889 | "is-core-module": { 1890 | "version": "2.2.0", 1891 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", 1892 | "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", 1893 | "dev": true, 1894 | "requires": { 1895 | "has": "^1.0.3" 1896 | } 1897 | }, 1898 | "is-extglob": { 1899 | "version": "2.1.1", 1900 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1901 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1902 | "dev": true 1903 | }, 1904 | "is-glob": { 1905 | "version": "4.0.1", 1906 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 1907 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 1908 | "dev": true, 1909 | "requires": { 1910 | "is-extglob": "^2.1.1" 1911 | } 1912 | }, 1913 | "is-number": { 1914 | "version": "7.0.0", 1915 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1916 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1917 | "dev": true 1918 | }, 1919 | "is-stream": { 1920 | "version": "2.0.0", 1921 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", 1922 | "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", 1923 | "dev": true 1924 | }, 1925 | "isexe": { 1926 | "version": "2.0.0", 1927 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1928 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1929 | "dev": true 1930 | }, 1931 | "jest-worker": { 1932 | "version": "26.6.2", 1933 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", 1934 | "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", 1935 | "dev": true, 1936 | "requires": { 1937 | "@types/node": "*", 1938 | "merge-stream": "^2.0.0", 1939 | "supports-color": "^7.0.0" 1940 | } 1941 | }, 1942 | "js-tokens": { 1943 | "version": "4.0.0", 1944 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1945 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 1946 | }, 1947 | "jsesc": { 1948 | "version": "2.5.2", 1949 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", 1950 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" 1951 | }, 1952 | "json-parse-better-errors": { 1953 | "version": "1.0.2", 1954 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 1955 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", 1956 | "dev": true 1957 | }, 1958 | "json-schema-traverse": { 1959 | "version": "0.4.1", 1960 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1961 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 1962 | }, 1963 | "json5": { 1964 | "version": "2.1.3", 1965 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", 1966 | "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", 1967 | "requires": { 1968 | "minimist": "^1.2.5" 1969 | } 1970 | }, 1971 | "loader-runner": { 1972 | "version": "4.1.0", 1973 | "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.1.0.tgz", 1974 | "integrity": "sha512-oR4lB4WvwFoC70ocraKhn5nkKSs23t57h9udUgw8o0iH8hMXeEoRuUgfcvgUwAJ1ZpRqBvcou4N2SMvM1DwMrA==", 1975 | "dev": true 1976 | }, 1977 | "loader-utils": { 1978 | "version": "2.0.0", 1979 | "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", 1980 | "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", 1981 | "dev": true, 1982 | "requires": { 1983 | "big.js": "^5.2.2", 1984 | "emojis-list": "^3.0.0", 1985 | "json5": "^2.1.2" 1986 | } 1987 | }, 1988 | "locate-path": { 1989 | "version": "6.0.0", 1990 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1991 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1992 | "dev": true, 1993 | "requires": { 1994 | "p-locate": "^5.0.0" 1995 | } 1996 | }, 1997 | "lodash": { 1998 | "version": "4.17.20", 1999 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 2000 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 2001 | }, 2002 | "make-dir": { 2003 | "version": "3.1.0", 2004 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 2005 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 2006 | "requires": { 2007 | "semver": "^6.0.0" 2008 | } 2009 | }, 2010 | "merge-stream": { 2011 | "version": "2.0.0", 2012 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 2013 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", 2014 | "dev": true 2015 | }, 2016 | "merge2": { 2017 | "version": "1.4.1", 2018 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 2019 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 2020 | "dev": true 2021 | }, 2022 | "micromatch": { 2023 | "version": "4.0.2", 2024 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", 2025 | "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", 2026 | "dev": true, 2027 | "requires": { 2028 | "braces": "^3.0.1", 2029 | "picomatch": "^2.0.5" 2030 | } 2031 | }, 2032 | "mime-db": { 2033 | "version": "1.44.0", 2034 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 2035 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", 2036 | "dev": true 2037 | }, 2038 | "mime-types": { 2039 | "version": "2.1.27", 2040 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 2041 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 2042 | "dev": true, 2043 | "requires": { 2044 | "mime-db": "1.44.0" 2045 | } 2046 | }, 2047 | "mimic-fn": { 2048 | "version": "2.1.0", 2049 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 2050 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", 2051 | "dev": true 2052 | }, 2053 | "minimist": { 2054 | "version": "1.2.5", 2055 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 2056 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 2057 | }, 2058 | "ms": { 2059 | "version": "2.1.2", 2060 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2061 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 2062 | }, 2063 | "neo-async": { 2064 | "version": "2.6.2", 2065 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 2066 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", 2067 | "dev": true 2068 | }, 2069 | "node-releases": { 2070 | "version": "1.1.67", 2071 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", 2072 | "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==" 2073 | }, 2074 | "normalize-path": { 2075 | "version": "3.0.0", 2076 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 2077 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 2078 | "dev": true 2079 | }, 2080 | "npm-run-path": { 2081 | "version": "4.0.1", 2082 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", 2083 | "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", 2084 | "dev": true, 2085 | "requires": { 2086 | "path-key": "^3.0.0" 2087 | } 2088 | }, 2089 | "object-keys": { 2090 | "version": "1.1.1", 2091 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 2092 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" 2093 | }, 2094 | "object.assign": { 2095 | "version": "4.1.2", 2096 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", 2097 | "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", 2098 | "requires": { 2099 | "call-bind": "^1.0.0", 2100 | "define-properties": "^1.1.3", 2101 | "has-symbols": "^1.0.1", 2102 | "object-keys": "^1.1.1" 2103 | } 2104 | }, 2105 | "once": { 2106 | "version": "1.4.0", 2107 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 2108 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 2109 | "dev": true, 2110 | "requires": { 2111 | "wrappy": "1" 2112 | } 2113 | }, 2114 | "onetime": { 2115 | "version": "5.1.2", 2116 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 2117 | "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 2118 | "dev": true, 2119 | "requires": { 2120 | "mimic-fn": "^2.1.0" 2121 | } 2122 | }, 2123 | "p-limit": { 2124 | "version": "3.1.0", 2125 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 2126 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 2127 | "dev": true, 2128 | "requires": { 2129 | "yocto-queue": "^0.1.0" 2130 | } 2131 | }, 2132 | "p-locate": { 2133 | "version": "5.0.0", 2134 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 2135 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 2136 | "dev": true, 2137 | "requires": { 2138 | "p-limit": "^3.0.2" 2139 | } 2140 | }, 2141 | "p-try": { 2142 | "version": "2.2.0", 2143 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 2144 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" 2145 | }, 2146 | "path-exists": { 2147 | "version": "4.0.0", 2148 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 2149 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" 2150 | }, 2151 | "path-key": { 2152 | "version": "3.1.1", 2153 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 2154 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 2155 | "dev": true 2156 | }, 2157 | "path-parse": { 2158 | "version": "1.0.6", 2159 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 2160 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 2161 | "dev": true 2162 | }, 2163 | "path-type": { 2164 | "version": "4.0.0", 2165 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 2166 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 2167 | "dev": true 2168 | }, 2169 | "picomatch": { 2170 | "version": "2.2.2", 2171 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 2172 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 2173 | "dev": true 2174 | }, 2175 | "pkg-dir": { 2176 | "version": "5.0.0", 2177 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", 2178 | "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", 2179 | "dev": true, 2180 | "requires": { 2181 | "find-up": "^5.0.0" 2182 | } 2183 | }, 2184 | "pump": { 2185 | "version": "3.0.0", 2186 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 2187 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 2188 | "dev": true, 2189 | "requires": { 2190 | "end-of-stream": "^1.1.0", 2191 | "once": "^1.3.1" 2192 | } 2193 | }, 2194 | "punycode": { 2195 | "version": "2.1.1", 2196 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 2197 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 2198 | }, 2199 | "randombytes": { 2200 | "version": "2.1.0", 2201 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 2202 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 2203 | "dev": true, 2204 | "requires": { 2205 | "safe-buffer": "^5.1.0" 2206 | } 2207 | }, 2208 | "rechoir": { 2209 | "version": "0.7.0", 2210 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", 2211 | "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", 2212 | "dev": true, 2213 | "requires": { 2214 | "resolve": "^1.9.0" 2215 | } 2216 | }, 2217 | "regenerate": { 2218 | "version": "1.4.2", 2219 | "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", 2220 | "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" 2221 | }, 2222 | "regenerate-unicode-properties": { 2223 | "version": "8.2.0", 2224 | "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", 2225 | "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", 2226 | "requires": { 2227 | "regenerate": "^1.4.0" 2228 | } 2229 | }, 2230 | "regenerator-runtime": { 2231 | "version": "0.13.7", 2232 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", 2233 | "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" 2234 | }, 2235 | "regenerator-transform": { 2236 | "version": "0.14.5", 2237 | "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", 2238 | "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", 2239 | "requires": { 2240 | "@babel/runtime": "^7.8.4" 2241 | } 2242 | }, 2243 | "regexpu-core": { 2244 | "version": "4.7.1", 2245 | "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", 2246 | "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", 2247 | "requires": { 2248 | "regenerate": "^1.4.0", 2249 | "regenerate-unicode-properties": "^8.2.0", 2250 | "regjsgen": "^0.5.1", 2251 | "regjsparser": "^0.6.4", 2252 | "unicode-match-property-ecmascript": "^1.0.4", 2253 | "unicode-match-property-value-ecmascript": "^1.2.0" 2254 | } 2255 | }, 2256 | "regjsgen": { 2257 | "version": "0.5.2", 2258 | "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", 2259 | "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" 2260 | }, 2261 | "regjsparser": { 2262 | "version": "0.6.4", 2263 | "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", 2264 | "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", 2265 | "requires": { 2266 | "jsesc": "~0.5.0" 2267 | }, 2268 | "dependencies": { 2269 | "jsesc": { 2270 | "version": "0.5.0", 2271 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", 2272 | "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" 2273 | } 2274 | } 2275 | }, 2276 | "resolve": { 2277 | "version": "1.19.0", 2278 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", 2279 | "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", 2280 | "dev": true, 2281 | "requires": { 2282 | "is-core-module": "^2.1.0", 2283 | "path-parse": "^1.0.6" 2284 | } 2285 | }, 2286 | "resolve-cwd": { 2287 | "version": "3.0.0", 2288 | "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", 2289 | "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", 2290 | "dev": true, 2291 | "requires": { 2292 | "resolve-from": "^5.0.0" 2293 | } 2294 | }, 2295 | "resolve-from": { 2296 | "version": "5.0.0", 2297 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", 2298 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", 2299 | "dev": true 2300 | }, 2301 | "reusify": { 2302 | "version": "1.0.4", 2303 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 2304 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 2305 | "dev": true 2306 | }, 2307 | "run-parallel": { 2308 | "version": "1.1.10", 2309 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", 2310 | "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", 2311 | "dev": true 2312 | }, 2313 | "safe-buffer": { 2314 | "version": "5.2.1", 2315 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2316 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 2317 | "dev": true 2318 | }, 2319 | "schema-utils": { 2320 | "version": "3.0.0", 2321 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", 2322 | "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", 2323 | "dev": true, 2324 | "requires": { 2325 | "@types/json-schema": "^7.0.6", 2326 | "ajv": "^6.12.5", 2327 | "ajv-keywords": "^3.5.2" 2328 | } 2329 | }, 2330 | "semver": { 2331 | "version": "6.3.0", 2332 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 2333 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 2334 | }, 2335 | "serialize-javascript": { 2336 | "version": "5.0.1", 2337 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", 2338 | "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", 2339 | "dev": true, 2340 | "requires": { 2341 | "randombytes": "^2.1.0" 2342 | } 2343 | }, 2344 | "shebang-command": { 2345 | "version": "2.0.0", 2346 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 2347 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 2348 | "dev": true, 2349 | "requires": { 2350 | "shebang-regex": "^3.0.0" 2351 | } 2352 | }, 2353 | "shebang-regex": { 2354 | "version": "3.0.0", 2355 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 2356 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 2357 | "dev": true 2358 | }, 2359 | "signal-exit": { 2360 | "version": "3.0.3", 2361 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 2362 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", 2363 | "dev": true 2364 | }, 2365 | "slash": { 2366 | "version": "3.0.0", 2367 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 2368 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 2369 | "dev": true 2370 | }, 2371 | "source-list-map": { 2372 | "version": "2.0.1", 2373 | "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", 2374 | "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", 2375 | "dev": true 2376 | }, 2377 | "source-map": { 2378 | "version": "0.6.1", 2379 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 2380 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 2381 | "dev": true 2382 | }, 2383 | "source-map-support": { 2384 | "version": "0.5.19", 2385 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 2386 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 2387 | "dev": true, 2388 | "requires": { 2389 | "buffer-from": "^1.0.0", 2390 | "source-map": "^0.6.0" 2391 | } 2392 | }, 2393 | "strip-final-newline": { 2394 | "version": "2.0.0", 2395 | "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", 2396 | "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", 2397 | "dev": true 2398 | }, 2399 | "supports-color": { 2400 | "version": "7.2.0", 2401 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 2402 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 2403 | "dev": true, 2404 | "requires": { 2405 | "has-flag": "^4.0.0" 2406 | } 2407 | }, 2408 | "tapable": { 2409 | "version": "2.2.0", 2410 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", 2411 | "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", 2412 | "dev": true 2413 | }, 2414 | "terser": { 2415 | "version": "5.5.1", 2416 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz", 2417 | "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==", 2418 | "dev": true, 2419 | "requires": { 2420 | "commander": "^2.20.0", 2421 | "source-map": "~0.7.2", 2422 | "source-map-support": "~0.5.19" 2423 | }, 2424 | "dependencies": { 2425 | "source-map": { 2426 | "version": "0.7.3", 2427 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", 2428 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", 2429 | "dev": true 2430 | } 2431 | } 2432 | }, 2433 | "terser-webpack-plugin": { 2434 | "version": "5.0.3", 2435 | "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.0.3.tgz", 2436 | "integrity": "sha512-zFdGk8Lh9ZJGPxxPE6jwysOlATWB8GMW8HcfGULWA/nPal+3VdATflQvSBSLQJRCmYZnfFJl6vkRTiwJGNgPiQ==", 2437 | "dev": true, 2438 | "requires": { 2439 | "jest-worker": "^26.6.1", 2440 | "p-limit": "^3.0.2", 2441 | "schema-utils": "^3.0.0", 2442 | "serialize-javascript": "^5.0.1", 2443 | "source-map": "^0.6.1", 2444 | "terser": "^5.3.8" 2445 | } 2446 | }, 2447 | "to-fast-properties": { 2448 | "version": "2.0.0", 2449 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 2450 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" 2451 | }, 2452 | "to-regex-range": { 2453 | "version": "5.0.1", 2454 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2455 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 2456 | "dev": true, 2457 | "requires": { 2458 | "is-number": "^7.0.0" 2459 | } 2460 | }, 2461 | "tslib": { 2462 | "version": "1.14.1", 2463 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 2464 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 2465 | "dev": true 2466 | }, 2467 | "unicode-canonical-property-names-ecmascript": { 2468 | "version": "1.0.4", 2469 | "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", 2470 | "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" 2471 | }, 2472 | "unicode-match-property-ecmascript": { 2473 | "version": "1.0.4", 2474 | "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", 2475 | "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", 2476 | "requires": { 2477 | "unicode-canonical-property-names-ecmascript": "^1.0.4", 2478 | "unicode-property-aliases-ecmascript": "^1.0.4" 2479 | } 2480 | }, 2481 | "unicode-match-property-value-ecmascript": { 2482 | "version": "1.2.0", 2483 | "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", 2484 | "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" 2485 | }, 2486 | "unicode-property-aliases-ecmascript": { 2487 | "version": "1.1.0", 2488 | "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", 2489 | "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" 2490 | }, 2491 | "uri-js": { 2492 | "version": "4.4.0", 2493 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", 2494 | "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", 2495 | "requires": { 2496 | "punycode": "^2.1.0" 2497 | } 2498 | }, 2499 | "v8-compile-cache": { 2500 | "version": "2.2.0", 2501 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", 2502 | "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", 2503 | "dev": true 2504 | }, 2505 | "watchpack": { 2506 | "version": "2.1.0", 2507 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.0.tgz", 2508 | "integrity": "sha512-UjgD1mqjkG99+3lgG36at4wPnUXNvis2v1utwTgQ43C22c4LD71LsYMExdWXh4HZ+RmW+B0t1Vrg2GpXAkTOQw==", 2509 | "dev": true, 2510 | "requires": { 2511 | "glob-to-regexp": "^0.4.1", 2512 | "graceful-fs": "^4.1.2" 2513 | } 2514 | }, 2515 | "webpack": { 2516 | "version": "5.11.1", 2517 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.1.tgz", 2518 | "integrity": "sha512-tNUIdAmYJv+nupRs/U/gqmADm6fgrf5xE+rSlSsf2PgsGO7j2WG7ccU6AWNlOJlHFl+HnmXlBmHIkiLf+XA9mQ==", 2519 | "dev": true, 2520 | "requires": { 2521 | "@types/eslint-scope": "^3.7.0", 2522 | "@types/estree": "^0.0.45", 2523 | "@webassemblyjs/ast": "1.9.1", 2524 | "@webassemblyjs/helper-module-context": "1.9.1", 2525 | "@webassemblyjs/wasm-edit": "1.9.1", 2526 | "@webassemblyjs/wasm-parser": "1.9.1", 2527 | "acorn": "^8.0.4", 2528 | "browserslist": "^4.14.5", 2529 | "chrome-trace-event": "^1.0.2", 2530 | "enhanced-resolve": "^5.3.1", 2531 | "eslint-scope": "^5.1.1", 2532 | "events": "^3.2.0", 2533 | "glob-to-regexp": "^0.4.1", 2534 | "graceful-fs": "^4.2.4", 2535 | "json-parse-better-errors": "^1.0.2", 2536 | "loader-runner": "^4.1.0", 2537 | "mime-types": "^2.1.27", 2538 | "neo-async": "^2.6.2", 2539 | "pkg-dir": "^5.0.0", 2540 | "schema-utils": "^3.0.0", 2541 | "tapable": "^2.1.1", 2542 | "terser-webpack-plugin": "^5.0.3", 2543 | "watchpack": "^2.0.0", 2544 | "webpack-sources": "^2.1.1" 2545 | } 2546 | }, 2547 | "webpack-cli": { 2548 | "version": "4.3.0", 2549 | "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.0.tgz", 2550 | "integrity": "sha512-gve+BBKrzMPTOYDjupzV8JchUznhVWMKtWM1hFIQWi6XoeLvGNoQwkrtMWVb+aJ437GgCKdta7sIn10v621pKA==", 2551 | "dev": true, 2552 | "requires": { 2553 | "@discoveryjs/json-ext": "^0.5.0", 2554 | "@webpack-cli/info": "^1.2.0", 2555 | "@webpack-cli/serve": "^1.2.0", 2556 | "colorette": "^1.2.1", 2557 | "commander": "^6.2.0", 2558 | "enquirer": "^2.3.6", 2559 | "execa": "^4.1.0", 2560 | "fastest-levenshtein": "^1.0.12", 2561 | "import-local": "^3.0.2", 2562 | "interpret": "^2.2.0", 2563 | "rechoir": "^0.7.0", 2564 | "v8-compile-cache": "^2.2.0", 2565 | "webpack-merge": "^4.2.2" 2566 | }, 2567 | "dependencies": { 2568 | "commander": { 2569 | "version": "6.2.1", 2570 | "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", 2571 | "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", 2572 | "dev": true 2573 | } 2574 | } 2575 | }, 2576 | "webpack-merge": { 2577 | "version": "4.2.2", 2578 | "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", 2579 | "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", 2580 | "dev": true, 2581 | "requires": { 2582 | "lodash": "^4.17.15" 2583 | } 2584 | }, 2585 | "webpack-sources": { 2586 | "version": "2.2.0", 2587 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz", 2588 | "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==", 2589 | "dev": true, 2590 | "requires": { 2591 | "source-list-map": "^2.0.1", 2592 | "source-map": "^0.6.1" 2593 | } 2594 | }, 2595 | "which": { 2596 | "version": "2.0.2", 2597 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 2598 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 2599 | "dev": true, 2600 | "requires": { 2601 | "isexe": "^2.0.0" 2602 | } 2603 | }, 2604 | "wrappy": { 2605 | "version": "1.0.2", 2606 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2607 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2608 | "dev": true 2609 | }, 2610 | "yocto-queue": { 2611 | "version": "0.1.0", 2612 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 2613 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 2614 | "dev": true 2615 | } 2616 | } 2617 | } 2618 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hotwire-go-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "dependencies": { 6 | "@babel/core": "^7.12.10", 7 | "@babel/preset-env": "^7.12.11", 8 | "@hotwired/turbo": "^7.0.0-beta.1", 9 | "babel-loader": "^8.2.2" 10 | }, 11 | "private": true, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "author": "", 16 | "license": "ISC", 17 | "devDependencies": { 18 | "copy-webpack-plugin": "^7.0.0", 19 | "webpack": "^5.11.1", 20 | "webpack-cli": "^4.3.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pkg/notice/notice.go: -------------------------------------------------------------------------------- 1 | // Package notice implements cookie-based flash/notice functionality for 2 | // persisting ephemeral state between requests 3 | package notice 4 | 5 | import ( 6 | "context" 7 | "net/http" 8 | ) 9 | 10 | type contextKey struct{} 11 | 12 | // ContextKey is the type-safe key for storing a notice 13 | var ContextKey = contextKey{} 14 | 15 | // Context is an http.Handler that parses a notice from a request's cookies. If 16 | // one is found, it's added to the request's Context and removed from cookies 17 | func Context(next http.Handler) http.Handler { 18 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 19 | notice := Get(r) 20 | if notice != "" { 21 | // Notice has been collected, so expire it now 22 | Clear(w) 23 | ctx := context.WithValue(r.Context(), ContextKey, notice) 24 | r = r.WithContext(ctx) 25 | } 26 | next.ServeHTTP(w, r) 27 | }) 28 | } 29 | 30 | // Set updates the notice on a given response 31 | func Set(w http.ResponseWriter, value string) { 32 | http.SetCookie(w, &http.Cookie{Name: "notice", Value: value, Path: "/"}) 33 | } 34 | 35 | // Clear removes a notice on a given response 36 | func Clear(w http.ResponseWriter) { 37 | http.SetCookie(w, &http.Cookie{Name: "notice", MaxAge: -1}) 38 | } 39 | 40 | // Get retrieves a notice on a given response 41 | func Get(r *http.Request) string { 42 | var notice string 43 | if noticeCookie, err := r.Cookie("notice"); err == nil { 44 | notice = noticeCookie.Value 45 | } 46 | return notice 47 | } 48 | -------------------------------------------------------------------------------- /pkg/pubsub/pubsub.go: -------------------------------------------------------------------------------- 1 | // Package pubsub implements an in-memory publish/subscribe mechanism. 2 | // 3 | // Please don't use this in production. 4 | package pubsub 5 | 6 | import ( 7 | "context" 8 | "errors" 9 | "time" 10 | 11 | "nhooyr.io/websocket" 12 | ) 13 | 14 | var subscriptions = make(map[uint]*Subscription) 15 | 16 | // Subscription represents a set of subscribers on a topic 17 | type Subscription struct { 18 | // The ID of the subscription 19 | ID uint 20 | // The channel that can be used to publish new content to the topic 21 | C chan []byte 22 | // A list of websocket connections that are subscribed to the topic. Updates 23 | // via the channel C will be fanned out to these 24 | Conns []*websocket.Conn 25 | 26 | listening bool 27 | } 28 | 29 | // Listen starts a Subscription listening for updates to publish to subscribers 30 | func (s *Subscription) Listen() { 31 | if s.listening { 32 | return 33 | } 34 | 35 | go func(s *Subscription) { 36 | for { 37 | select { 38 | case msg := <-s.C: 39 | for i := range s.Conns { 40 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 41 | s.Conns[i].Write(ctx, websocket.MessageText, msg) 42 | cancel() 43 | } 44 | } 45 | } 46 | }(s) 47 | } 48 | 49 | // Subscribe adds the given websocket as a subscriber to the topic denoted by id 50 | func Subscribe(id uint, conn *websocket.Conn) { 51 | sub, ok := subscriptions[id] 52 | if !ok { 53 | sub = &Subscription{ID: id, C: make(chan []byte), Conns: []*websocket.Conn{conn}} 54 | sub.Listen() 55 | subscriptions[id] = sub 56 | return 57 | } 58 | sub.Conns = append(sub.Conns, conn) 59 | } 60 | 61 | // Publish publishes content to all subscribers of the topic denoted by id 62 | func Publish(id uint, content []byte) error { 63 | sub, ok := subscriptions[id] 64 | if !ok { 65 | return errors.New("No one's listening") 66 | } 67 | sub.C <- content 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /pkg/timefmt/timefmt.go: -------------------------------------------------------------------------------- 1 | // Package timefmt implements time formatting utilities 2 | package timefmt 3 | 4 | import ( 5 | "strings" 6 | "time" 7 | ) 8 | 9 | // FuncMap is a map of the provided functions of this package that can be used 10 | // with the Go template package 11 | var FuncMap = map[string]interface{}{ 12 | "prettyTime": PrettyTime, 13 | } 14 | 15 | // PrettyTime returns a truncated version of a RubyTime formatted time.Time 16 | // Note: there's probably a standard-library way of doing this, but Go's time 17 | // formatting is ridiculous, so this was faster than figuring it out. 18 | func PrettyTime(t time.Time) string { 19 | // e.g. Mon Jan 02 15:04:05 -0700 2006 20 | s := t.Local().Format(time.RubyDate) 21 | fields := strings.Split(s, " ") 22 | 23 | // e.g. Jan 02 15:04:05 24 | return strings.Join(fields[1:4], " ") 25 | } 26 | -------------------------------------------------------------------------------- /routes/route.go: -------------------------------------------------------------------------------- 1 | // Package routes wires up request paths to their Controllers 2 | package routes 3 | 4 | import ( 5 | "github.com/go-chi/chi" 6 | "github.com/while1malloc0/hotwire-go-example/controllers" 7 | "github.com/while1malloc0/hotwire-go-example/pkg/notice" 8 | ) 9 | 10 | // Register wires up request paths to controllers for the given router 11 | func Register(r chi.Router) { 12 | roomsController := &controllers.RoomsController{} 13 | messagesController := &controllers.MessagesController{} 14 | 15 | // parse notices out of cookies if they exist. Useful for one-off storage 16 | // between requests. 17 | r.Use(notice.Context) 18 | 19 | // Root route, i.e. / 20 | r.Get("/", roomsController.Index) 21 | 22 | r.Route("/rooms", func(r chi.Router) { 23 | r.Get("/", roomsController.Index) // GET /rooms 24 | r.Get("/new", roomsController.New) // GET /rooms/new 25 | r.Post("/", roomsController.Create) // POST /rooms 26 | 27 | r.Route("/{id}", func(r chi.Router) { 28 | // parse a room out of the {id} param 29 | r.Use(roomsController.Context) 30 | 31 | r.Get("/", roomsController.Get) // GET /rooms/{id} 32 | r.Post("/", roomsController.Update) // POST /rooms/{id} 33 | 34 | r.Get("/edit", roomsController.Edit) // GET /rooms/{id}/edit 35 | r.Get("/destroy", roomsController.Destroy) // GET /rooms/{id}/destroy 36 | 37 | r.Route("/messages", func(r chi.Router) { 38 | r.Post("/", messagesController.Create) // POST /rooms/{id}/messages 39 | 40 | r.Get("/new", messagesController.New) // GET /rooms/{id}/messages/new 41 | r.Get("/socket", messagesController.Socket) // GET /rooms/{id}/messages/socket 42 | }) 43 | }) 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /scripts/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd "$(dirname "$0")/.." || exit 1 4 | 5 | set -euo pipefail 6 | 7 | echo "Checking for node" 8 | command -v npm &> /dev/null || { echo "npm not found. Install it and try again."; exit 1; } 9 | 10 | echo "Checking for go" 11 | command -v go &> /dev/null || { echo "go not found. Install it and try again."; exit 1; } 12 | 13 | echo "Installing Go deps" 14 | go mod download 1>/dev/null 2>err.log || { echo "Failed to install Go deps. Saved error to err.log"; cat err.log; exit 1; } 15 | 16 | echo "Installing node deps" 17 | npm install 1>/dev/null 2>err.log || { echo "Failed to install node deps. Saved error to err.log"; cat err.log; exit 1; } 18 | 19 | echo "Creating webpack bundle" 20 | npx webpack -c webpack.config.js --mode development 1>/dev/null 2>err.log || { echo "Failed to created webpack bundle. Saved error to err.log"; cat err.log; exit 1; } 21 | 22 | rm err.log &> /dev/null 23 | 24 | echo "Successfully bootstrapped project dependencies" -------------------------------------------------------------------------------- /scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd "$(dirname "$0")/.." || exit 1 4 | 5 | ./scripts/bootstrap.sh 6 | 7 | echo "Successfully setup project. Run the server with 'go run main.go'" -------------------------------------------------------------------------------- /templates/layout.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Chat 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{ yield }} 12 | 13 | -------------------------------------------------------------------------------- /templates/messages/_message.gohtml: -------------------------------------------------------------------------------- 1 | {{ define "message" }} 2 |

3 | {{ .CreatedAt | prettyTime }}: {{ .Content }} 4 |

5 | {{ end }} -------------------------------------------------------------------------------- /templates/messages/create.turbostream.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /templates/messages/new.gohtml: -------------------------------------------------------------------------------- 1 |

New Message

2 | 3 | 4 |
5 |
6 | 7 | 8 |
9 |
10 |
11 | 12 | Back -------------------------------------------------------------------------------- /templates/rooms/_form.gohtml: -------------------------------------------------------------------------------- 1 | {{ define "form" }} 2 |
3 |
4 | 5 | 6 |
7 | 8 |
9 |
10 |
11 | {{ end }} -------------------------------------------------------------------------------- /templates/rooms/_room.gohtml: -------------------------------------------------------------------------------- 1 | {{ define "room" }} 2 |

3 | Name: 4 | {{ .Room.Name }} 5 |

6 | {{ end }} -------------------------------------------------------------------------------- /templates/rooms/edit.gohtml: -------------------------------------------------------------------------------- 1 |

Editing Room

2 | 3 | 4 | {{ template "form" . }} 5 | 6 | 7 | Show | 8 | Back -------------------------------------------------------------------------------- /templates/rooms/index.gohtml: -------------------------------------------------------------------------------- 1 |

{{ .Notice }}

2 | 3 |

Rooms

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{ range .Rooms }} 15 | 16 | 17 | 18 | 19 | 20 | 21 | {{ end }} 22 | 23 |
Name
{{ .Name }}ShowEditDestroy
24 | 25 |
26 | 27 | New Room -------------------------------------------------------------------------------- /templates/rooms/new.gohtml: -------------------------------------------------------------------------------- 1 |

New Room

2 | 3 |
4 |
5 | 6 | 7 |
8 |
9 | 10 |
11 |
12 | 13 | Back -------------------------------------------------------------------------------- /templates/rooms/show.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ template "room" . }} 5 |

6 | Edit | 7 | Back 8 |

9 |
10 | 11 |
12 | {{ range .Room.Messages }} 13 | {{ template "message" . }} 14 | {{ end }} 15 |
16 | 17 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const CopyPlugin = require("copy-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: { 6 | bundle: "./assets/js/index.js", 7 | }, 8 | output: { 9 | filename: "[name].js", 10 | path: path.resolve(__dirname, "public/js"), 11 | }, 12 | devtool: "source-map", 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.js$/, 17 | exclude: [/node_modules/], 18 | use: [{ loader: "babel-loader" }], 19 | }, 20 | ], 21 | }, 22 | plugins: [ 23 | new CopyPlugin({ 24 | patterns: [{ from: "assets/css", to: "../css" }], 25 | }), 26 | ], 27 | }; 28 | --------------------------------------------------------------------------------