diff --git a/backend/blockchain.go b/backend/blockchain.go index c6b0e91..1d0dc2a 100644 --- a/backend/blockchain.go +++ b/backend/blockchain.go @@ -10,24 +10,76 @@ package surge import ( "log" + "strconv" + "github.com/nknorg/nkn-sdk-go" "github.com/rule110-io/surge/backend/constants" ) -func subscribeToPubSub(topic string) { - txnHash, err := client.Subscribe("", topic, constants.SubscriptionDuration, "Surge Beta Client", nil) +var TransactionFee string + +func subscribeToPubSub(topic string) bool { + config := &nkn.DefaultTransactionConfig + + calculatedFee, err := CalculateFee(TransactionFee) + if err != nil { + pushError("Error on subscribe to topic", err.Error()) + return false + } + config.Fee = calculatedFee + + feeFloat, _ := strconv.ParseFloat(config.Fee, 64) + hasBalance, _ := ValidateBalanceForTransaction(0, feeFloat, true) + if !hasBalance { + pushError("Error on subscribe to topic", "Not enough fee in wallet, consider depositing NKN or if possible lower transaction fees in the wallet settings.") + updateTopicSubscriptionState(topic, 0) + return false + } + + updateTopicSubscriptionState(topic, 1) + txnHash, err := client.Subscribe("", topic, constants.SubscriptionDuration, constants.TransactionMeta, config) if err != nil { - log.Println("Probably already subscribed to:", topic, "error:", err) + log.Println("Subsription transaction failed for topic:", topic, "error:", err) + updateTopicSubscriptionState(topic, 1) + return false } else { - log.Println("Subscribed: ", topic, txnHash) + log.Println("Subscribed: ", topic, txnHash, "fee paid:", config.Fee) } + updateTopicSubscriptionState(topic, 2) + return true } -func unsubscribeToPubSub(topic string) { - txnHash, err := client.Unsubscribe("", topic, nil) +func unsubscribeToPubSub(topic string) bool { + config := &nkn.DefaultTransactionConfig + + var err error = nil + config.Fee, err = CalculateFee(TransactionFee) + if err != nil { + pushError("Error on unsubscribe to topic", err.Error()) + return false + } + + initialState := 0 + currentState, exists := topicEncodedSubcribeStateMap[topic] + if exists { + initialState = currentState + } + + feeFloat, _ := strconv.ParseFloat(config.Fee, 64) + hasBalance, _ := ValidateBalanceForTransaction(0, feeFloat, true) + if !hasBalance { + pushError("Error on unsubscribe to topic", "Not enough fee in wallet, consider depositing NKN or if possible lower transaction fees in the wallet settings.") + updateTopicSubscriptionState(topic, initialState) + return false + } + updateTopicSubscriptionState(topic, 1) + + txnHash, err := client.Unsubscribe("", topic, config) if err != nil { log.Println("Probably not subscribed to:", topic, "error:", err) } else { - log.Println("Unsubscribed: ", topic, txnHash) + log.Println("Unsubscribed: ", topic, txnHash, "fee paid:", config.Fee) } + updateTopicSubscriptionState(topic, 0) + return true } diff --git a/backend/client.go b/backend/client.go index f098e60..79a9c65 100644 --- a/backend/client.go +++ b/backend/client.go @@ -72,7 +72,7 @@ func WailsBind(ctx *context.Context) { for !clientInitialized { time.Sleep(time.Second) if tryCount%10 == 0 { - pushError("Connection to NKN not yet established 0", "do you have an active internet connection?") + pushError("Connection to NKN not yet established", "do you have an active internet connection?") } tryCount++ } @@ -82,6 +82,7 @@ func WailsBind(ctx *context.Context) { go updateFileDataWorker() FrontendReady = true + log.Println("Frontend connected") } //InitializeClient Initiates the surge client and instantiates connection with the NKN network @@ -90,7 +91,7 @@ func InitializeClient(args []string) bool { account := InitializeAccount() client, err = nkn.NewMultiClient(account, "", getNumberClients(), false, &nkn.ClientConfig{ - ConnectRetries: 1000, + ConnectRetries: 10, SeedRPCServerAddr: GetBootstrapRPC(), }) if err != nil { @@ -130,6 +131,14 @@ func InitializeClient(args []string) bool { } messaging.Initialize(client, client.Account(), MessageReceived) + + //Get the transaction fee setting + TransactionFee, err = DbReadSetting("defaultTxFee") + if err != nil { + DbWriteSetting("defaultTxFee", "0") + TransactionFee = "0" + } + go autoSubscribeWorker() go platform.WatchOSXHandler() @@ -170,6 +179,10 @@ func StopClient() { //Persist our connections for future bootstraps PersistRPC(client) + for _, v := range topicsMap { + log.Println("Disconnecting from topic", v.Name) + AnnounceDisconnect(v.Name) + } client.Close() } @@ -201,8 +214,7 @@ func DownloadFileByHash(Hash string) bool { numChunks := int((file.FileSize-1)/int64(constants.ChunkSize)) + 1 //When downloading from remote enter file into db - dbFile, err := dbGetFile(Hash) - log.Println(dbFile) + _, err = dbGetFile(Hash) if err != nil { file.Path = path file.NumChunks = numChunks @@ -217,7 +229,7 @@ func DownloadFileByHash(Hash string) bool { randomChunks[i] = i } rand.Seed(time.Now().UnixNano()) - rand.Shuffle(len(randomChunks), func(i, j int) { randomChunks[i], randomChunks[j] = randomChunks[j], randomChunks[i] }) + //rand.Shuffle(len(randomChunks), func(i, j int) { randomChunks[i], randomChunks[j] = randomChunks[j], randomChunks[i] }) downloadChunks(file, randomChunks) @@ -244,17 +256,11 @@ func restartDownload(Hash string) { //Nothing more to download if numChunks == 0 { - platform.ShowNotification("Download Finished", "Download for "+file.FileName+" finished!") - pushNotification("Download Finished", file.FileName) - file.IsDownloading = false - file.IsUploading = true - file.IsAvailable = true - dbInsertFile(*file) return } rand.Seed(time.Now().UnixNano()) - rand.Shuffle(numChunks, func(i, j int) { missingChunks[i], missingChunks[j] = missingChunks[j], missingChunks[i] }) + //rand.Shuffle(numChunks, func(i, j int) { missingChunks[i], missingChunks[j] = missingChunks[j], missingChunks[i] }) log.Println("Restarting Download for", file.FileName) @@ -292,7 +298,7 @@ func onClientConnected(session *sessionmanager.Session, isDialIn bool) { go updateNumClientStore() addr := session.Session.RemoteAddr().String() - fmt.Println(string("\033[36m"), "Client Connected", addr, string("\033[0m")) + log.Println("Client Connected", addr) go listenToSession(session) } @@ -303,12 +309,8 @@ func onClientDisconnected(addr string) { mutexes.ListedFilesLock.Lock() defer mutexes.ListedFilesLock.Unlock() - //Remove this address from remote file seeders - for i := 0; i < len(ListedFiles); i++ { - fmt.Println(string("\033[31m"), "onClientDisconnected", ListedFiles[i].FileName) - } - RemoveSeeder(addr) + log.Println("Client Disconnected", addr) //Remove empty seeders listings for i := 0; i < len(ListedFiles); i++ { @@ -327,12 +329,10 @@ func listenToSession(Session *sessionmanager.Session) { addr := Session.Session.RemoteAddr().String() - fmt.Println(string("\033[31m"), "Initiate Session", addr, string("\033[0m")) + log.Println("Initiate Session", addr) for Session.Session != nil { data, chunkType, err := SessionRead(Session) - fmt.Println(string("\033[31m"), "Read data from session", addr, string("\033[0m")) - if err != nil { log.Println("Session read failed, closing session error:", err) break @@ -343,7 +343,7 @@ func listenToSession(Session *sessionmanager.Session) { switch chunkType { case constants.SurgeChunkID: //Write add to download internally after parsing data - processChunk(Session, data) + go processChunk(Session, data) } } } @@ -355,7 +355,6 @@ func processChunk(Session *sessionmanager.Session, Data []byte) { if err := proto.Unmarshal(Data, surgeMessage); err != nil { log.Panic("Failed to parse surge message:", err) } - fmt.Println(string("\033[31m"), "PROCESSING CHUNK", string("\033[0m")) //Write add to download mutexes.BandwidthAccumulatorMapLock.Lock() @@ -364,7 +363,7 @@ func processChunk(Session *sessionmanager.Session, Data []byte) { //Data nill means its a request for data if surgeMessage.Data == nil { - go TransmitChunk(Session, surgeMessage.FileID, surgeMessage.ChunkID) + TransmitChunk(Session, surgeMessage.FileID, surgeMessage.ChunkID) } else { //If data is not nill we are receiving data //When we receive a chunk mark it as no longer in transit @@ -381,7 +380,7 @@ func processChunk(Session *sessionmanager.Session, Data []byte) { } mutexes.WorkerMapLock.Unlock() - go WriteChunk(surgeMessage.FileID, surgeMessage.ChunkID, surgeMessage.Data) + WriteChunk(surgeMessage.FileID, surgeMessage.ChunkID, surgeMessage.Data) } } diff --git a/backend/communication.go b/backend/communication.go index 9c80811..9246b82 100644 --- a/backend/communication.go +++ b/backend/communication.go @@ -1,7 +1,6 @@ package surge import ( - "fmt" "strconv" "strings" @@ -9,6 +8,7 @@ import ( "github.com/rule110-io/surge/backend/messaging" "github.com/rule110-io/surge/backend/models" "github.com/rule110-io/surge/backend/mutexes" + "github.com/rule110-io/surge/backend/sessionmanager" ) const ( @@ -16,31 +16,28 @@ const ( MessageIDAnnounceFilesReply MessageIDAnnounceNewFile MessageIDAnnounceRemoveFile + MessageIDAnnounceDisconnect ) func MessageReceived(msg *messaging.MessageReceivedObj) { - fmt.Println(string("\033[36m"), "MESSAGE RECEIVED", string(msg.Data)) - fmt.Println(msg.Data) - switch msg.Type { case MessageIDAnnounceFiles: - SendAnnounceFilesReply(msg) - processQueryResponse(msg.Sender, msg.Data) + if msg.Sender != GetAccountAddress() { + go SendAnnounceFilesReply(msg) + } + go processQueryResponse(msg.Sender, msg.Data) case MessageIDAnnounceFilesReply: - //process file data - processQueryResponse(msg.Sender, msg.Data) + go processQueryResponse(msg.Sender, msg.Data) case MessageIDAnnounceNewFile: - //process file data - processQueryResponse(msg.Sender, msg.Data) + go processQueryResponse(msg.Sender, msg.Data) case MessageIDAnnounceRemoveFile: - processRemoveFile(string(msg.Data), msg.Sender) + go processRemoveFile(string(msg.Data), msg.Sender) + case MessageIDAnnounceDisconnect: + go sessionmanager.CloseSession(msg.Sender) } - } func AnnounceFiles(topicEncoded string) { - fmt.Println(string("\033[36m"), "ANNOUNCING FILES FOR TOPIC", topicEncoded) - payload := getTopicPayload(topicEncoded) dataObj := messaging.MessageObj{ @@ -53,8 +50,6 @@ func AnnounceFiles(topicEncoded string) { } func SendAnnounceFilesReply(msg *messaging.MessageReceivedObj) { - fmt.Println(string("\033[36m"), "SENDING FILE REQUEST REPLY", msg.TopicEncoded, msg.Sender) - payload := getTopicPayload(msg.TopicEncoded) if len(payload) > 0 { @@ -69,8 +64,6 @@ func SendAnnounceFilesReply(msg *messaging.MessageReceivedObj) { } func AnnounceNewFile(file *models.File) { - fmt.Println(string("\033[36m"), "ANNOUNCE NEW FILE FOR TOPIC", file.Topic) - //Create payload payload := surgeGenerateTopicPayload(file.FileName, file.FileSize, file.FileHash, file.Topic) @@ -85,8 +78,6 @@ func AnnounceNewFile(file *models.File) { } func AnnounceRemoveFile(topic string, fileHash string) { - fmt.Println(string("\033[36m"), "ANNOUNCE REMOVE FILE FOR TOPIC ", topic, " hash: ", fileHash) - //Create the data object dataObj := messaging.MessageObj{ Type: MessageIDAnnounceRemoveFile, @@ -97,9 +88,17 @@ func AnnounceRemoveFile(topic string, fileHash string) { messaging.Broadcast(&dataObj) } -func processRemoveFile(hash string, seeder string) { - fmt.Println(string("\033[36m"), "PROCESS REMOVE FILE FOR TOPIC, hash:", hash, " seeder: ", seeder) +func AnnounceDisconnect(topic string) { + //Create the data object + dataObj := messaging.MessageObj{ + Type: MessageIDAnnounceDisconnect, + TopicEncoded: TopicEncode(topic), + } + + messaging.Broadcast(&dataObj) +} +func processRemoveFile(hash string, seeder string) { RemoveFileSeeder(hash, seeder) mutexes.ListedFilesLock.Lock() @@ -121,8 +120,6 @@ func processQueryResponse(seeder string, Data []byte) { //Try to parse SurgeMessage s := string(Data) - fmt.Println(string("\033[36m"), "file query response received", seeder, string("\033[0m")) - mutexes.ListedFilesLock.Lock() //Parse the response diff --git a/backend/constants/configs.go b/backend/constants/configs.go index dbca77b..c7943c3 100644 --- a/backend/constants/configs.go +++ b/backend/constants/configs.go @@ -24,10 +24,13 @@ const ( NumWorkersMax = 12 //duration of a subscription blocktime is ~20sec - SubscriptionDuration = 180 + SubscriptionDuration = 4000 //official surge wallets TeamAddressA = "7a48870a43d1512e467e8df103b1dee8d908f297ffe1fb45e81317965597bc7c" TeamAddressB = "44734f736b31e522e9be64a812cf42d0822c765f4bc13404d3169ff8e3d54c9e" TeamAddressC = "68a10e26288b9e97fc97362eb935574dd3db74004f0081918ee121d15ed1d29b" + + //Meta payload for onchain transactions + TransactionMeta = "Surge 2.0 Client" ) diff --git a/backend/db.go b/backend/db.go index c16cc09..35ddbc2 100644 --- a/backend/db.go +++ b/backend/db.go @@ -77,7 +77,7 @@ func dbGetAllFiles() []models.File { return nil }); err != nil { - log.Println(err) + log.Println("Get all db files error:", err) } else { return files } @@ -137,7 +137,7 @@ func dbDeleteFile(Hash string) error { } return nil }); err != nil { - log.Println(err) + log.Println("Db delete file", err) return err } return nil diff --git a/backend/file.go b/backend/file.go index 9fe5be6..3f9c087 100644 --- a/backend/file.go +++ b/backend/file.go @@ -9,6 +9,7 @@ package surge import ( + "log" "os" bitmap "github.com/boljen/go-bitmap" @@ -126,6 +127,7 @@ func RemoveFileByHash(Hash string, FromDisk bool) bool { } mutexes.FileWriteLock.Unlock() + log.Println("Removing file:", file.FileName, file.FileHash, "from disk:", FromDisk) AnnounceRemoveFile(file.Topic, file.FileHash) return true } diff --git a/backend/io.go b/backend/io.go index 3a1114e..6f5852c 100644 --- a/backend/io.go +++ b/backend/io.go @@ -26,10 +26,11 @@ import ( ) func emitNotificationEvent(event string, title string, text string) { - runtime.EventsEmit(*wailsContext, "notificationEvent", title, text, time.Now().Unix()) + runtime.EventsEmit(*wailsContext, event, title, text, time.Now().Unix()) } func pushNotification(title string, text string) { + log.Println(title, text) //If wails frontend is not yet bound, we wait in a task to not block main thread if !FrontendReady { waitAndPush := func() { diff --git a/backend/messaging/pubsubclient.go b/backend/messaging/pubsubclient.go index 2785a81..4e33747 100644 --- a/backend/messaging/pubsubclient.go +++ b/backend/messaging/pubsubclient.go @@ -2,7 +2,6 @@ package messaging import ( "encoding/json" - "fmt" "log" nkn "github.com/nknorg/nkn-sdk-go" @@ -25,16 +24,14 @@ func Initialize(client *nkn.MultiClient, account *nkn.Account, onMsgHandler func func Broadcast(msg *MessageObj) { jsonObj, err := json.Marshal(msg) if err != nil { - fmt.Println(err) + log.Println("Broadcast json marshal:", err) } - fmt.Println("Marshalled Bytes:", jsonObj) - err = nknClient.PublishBinary(msg.TopicEncoded, jsonObj, &nkn.MessageConfig{ TxPool: true, }) if err != nil { - fmt.Println(err) + log.Println("Broadcast send binary:", err) } } @@ -42,19 +39,22 @@ func (msgReceived MessageReceivedObj) Reply(msg *MessageObj) { jsonObj, err := json.Marshal(msg) if err != nil { - fmt.Println(err) + log.Println("Reply json marshal:", err) return } - fmt.Println("Marshalled Bytes:", jsonObj) - - nknClient.SendBinary(nkn.NewStringArray(msgReceived.Sender), jsonObj, &nkn.MessageConfig{ + _, err = nknClient.SendBinary(nkn.NewStringArray(msgReceived.Sender), jsonObj, &nkn.MessageConfig{ TxPool: true, }) + if err != nil { + log.Println("Reply send binary:", err) + return + } + } func listen() { - for true { + for { //Wait for a message msg := <-nknClient.OnMessage.C @@ -64,8 +64,7 @@ func listen() { err := json.Unmarshal(msg.Data, &msgObj) if err != nil { log.Println("Received invalid message:", string(msg.Data), "from:", msg.Src, "error:", err) - fmt.Println("Received invalid message:", string(msg.Data), "from:", msg.Src, "error:", err) - } else if msg.Src == nknClient.Address() { + //} else if msg.Src == nknClient.Address() { //We exclude messages from ourselves } else { msgObj.Sender = msg.Src diff --git a/backend/middleware.go b/backend/middleware.go index 6dec024..00f1fa3 100644 --- a/backend/middleware.go +++ b/backend/middleware.go @@ -1,6 +1,11 @@ package surge import ( + "fmt" + "strconv" + "strings" + + "github.com/nknorg/nkn-sdk-go" "github.com/rule110-io/surge/backend/constants" "github.com/rule110-io/surge/backend/models" "github.com/rule110-io/surge/backend/mutexes" @@ -102,16 +107,22 @@ func (s *MiddlewareFunctions) StartDownloadMagnetLinks(Magnetlinks string) bool } //SubscribeToTopic subscribes to given topic -func (s *MiddlewareFunctions) SubscribeToTopic(Topic string) { +func (s *MiddlewareFunctions) SubscribeToTopic(Topic string) bool { if len(Topic) == 0 { - pushError("Error on Subscribe", "topic name of length zero.") + pushError("Error on Subscribe", "channel name of length zero.") + return false } else { - subscribeToSurgeTopic(Topic, true) + result, err := subscribeToSurgeTopic(Topic, true) + if err != nil { + return false + } else { + return result + } } } -func (s *MiddlewareFunctions) UnsubscribeFromTopic(Topic string) { - unsubscribeFromSurgeTopic(Topic) +func (s *MiddlewareFunctions) UnsubscribeFromTopic(Topic string) bool { + return unsubscribeFromSurgeTopic(Topic) } func (s *MiddlewareFunctions) GetTopicSubscriptions() []models.TopicInfo { @@ -187,7 +198,6 @@ func (s *MiddlewareFunctions) GetFileDetails(FileHash string) FileDetails { } } func (s *MiddlewareFunctions) GetTopicDetails(Topic string) models.TopicInfo { - return GetTopicInfo(Topic) } @@ -205,3 +215,106 @@ func (s *MiddlewareFunctions) SetDownloadFolder() bool { DbWriteSetting("downloadFolder", path) return true } + +func (s *MiddlewareFunctions) GetWalletAddress() string { + return WalletAddress() +} + +func (s *MiddlewareFunctions) GetWalletBalance() string { + return WalletBalance() +} +func (s *MiddlewareFunctions) TransferToRecipient(Recipient string, Amount string, Fee string) string { + //Validate recipient, can take both NKN address and PubKey (which we turn into NKN address) + walletAddr := "" + if strings.HasPrefix(Recipient, "NKN") { + walletAddr = Recipient + } else { + walletAddr, _ = nkn.ClientAddrToWalletAddr(Recipient) + } + err := nkn.VerifyWalletAddress(walletAddr) + if err != nil { + pushError("Transfer failed", "recipient address is not a valid nkn address.") + } + + //Check amount is valid + amountFloat, err := strconv.ParseFloat(Amount, 64) + if err != nil { + pushError("Error on transfer", "invalid amount: "+err.Error()) + return "" + } + + calculatedFee, err := CalculateFee(Fee) + if err != nil { + pushError("Error on transfer", err.Error()) + return "" + } + + calculatedFeeFloat, err := strconv.ParseFloat(calculatedFee, 64) + if err != nil { + pushError("Error on transfer", "invalid fee: "+err.Error()) + return "" + } + + isEnough, balanceError := ValidateBalanceForTransaction(amountFloat, calculatedFeeFloat, false) + if !isEnough { + pushError("Error on tip", "transaction failed: "+balanceError.Error()) + return "" + } + + _, hash := WalletTransfer(walletAddr, Amount, calculatedFee) + return hash +} + +func (s *MiddlewareFunctions) GetTxFee() string { + return TransactionFee +} + +func (s *MiddlewareFunctions) SetTxFee(Fee string) { + TransactionFee = Fee + DbWriteSetting("defaultTxFee", Fee) +} + +func (s *MiddlewareFunctions) Tip(FileHash string, Amount string, Fee string) { + amountFloat, err := strconv.ParseFloat(Amount, 64) + + if err != nil { + pushError("Error on tip", "Invalid amount.") + return + } + + if amountFloat < 0.00000001 { + pushError("Error on tip", "Minimum tip amount is 0.00000001") + return + } + + seeders := GetSeeders(FileHash) + if len(seeders) == 0 { + pushError("Error on tip", "No seeders found to tip.") + return + } + + share := amountFloat / float64(len(GetSeeders(FileHash))) + calculatedFee, err := CalculateFee(Fee) + if err != nil { + pushError("Error on transfer", "invalid fee: "+err.Error()) + return + } + + feePerTxFloat, _ := strconv.ParseFloat(calculatedFee, 64) + totalFeeFloat := feePerTxFloat * float64(len(seeders)) + + isEnough, balanceError := ValidateBalanceForTransaction(amountFloat, totalFeeFloat, false) + if !isEnough { + pushError("Error on tip", balanceError.Error()) + return + } + + for _, v := range seeders { + walletAddr, _ := nkn.ClientAddrToWalletAddr(v) + success, _ := WalletTransfer(walletAddr, fmt.Sprintf("%f", share), calculatedFee) + + if !success { + break + } + } +} diff --git a/backend/models/topic.go b/backend/models/topic.go index 6ae4596..c1f2333 100644 --- a/backend/models/topic.go +++ b/backend/models/topic.go @@ -6,8 +6,9 @@ type Topic struct { } type TopicInfo struct { - Name string - Subscribers int - FileCount int - Permissions TopicPermissions + Name string + Subscribers int + FileCount int + Permissions TopicPermissions + SubscriptionState int } diff --git a/backend/network.go b/backend/network.go index 7905a9e..cd5aa91 100644 --- a/backend/network.go +++ b/backend/network.go @@ -55,7 +55,9 @@ func fileBandwidth(FileID string) (Download int, Upload int) { return int(fileBandwidthMap[FileID].Download.Avg()), int(fileBandwidthMap[FileID].Upload.Avg()) } -func downloadChunks(file *models.File, randomChunks []int) { //, mutateSeederLock *sync.Mutex, activeSeeders *[]string) { +func downloadChunks(file *models.File, randomChunks []int) { + log.Println("Starting download for file:", file.FileName, file.FileHash, "size:", file.FileSize) + fileID := file.FileHash //todo: lock seeders @@ -89,20 +91,8 @@ func downloadChunks(file *models.File, randomChunks []int) { //, mutateSeederLoc defer terminate(terminateFlag) for i := 0; i < numChunks; i++ { - fmt.Println(numChunks) - fmt.Println(string("\033[36m"), "Preparing Chunk Fetch", string("\033[0m")) - dbFile, err := dbGetFile(fileID) - //DEBUG CODE REMOVE THIS SUPER INEFFICIENT: - /*var missingChunks []int - for i := 0; i < dbFile.NumChunks; i++ { - if !bitmap.Get(dbFile.ChunkMap, i) { - missingChunks = append(missingChunks, i) - } - } - fmt.Println(missingChunks)*/ - //Check if file is still tracked in surge if err != nil { log.Println("Download Job Terminated", "File no longer in DB") @@ -443,10 +433,10 @@ func SessionRead(Session *sessionmanager.Session) (data []byte, ID byte, err err _, err = io.ReadFull(Session.Reader, headerBuffer) if err != nil { if err.Error() == "session closed" { - log.Println(err) + log.Println("Session read", err) return nil, 0x0, err } - log.Println(err) + log.Println("Session read", err) return nil, 0x0, err } @@ -463,7 +453,7 @@ func SessionRead(Session *sessionmanager.Session) (data []byte, ID byte, err err // read the full message, or return an error _, err = io.ReadFull(Session.Reader, data[:int(size)]) if err != nil { - log.Println(err) + log.Println("Session read", err) return nil, 0x0, err } diff --git a/backend/openapi/openapi.go b/backend/openapi/openapi.go new file mode 100644 index 0000000..af7f94a --- /dev/null +++ b/backend/openapi/openapi.go @@ -0,0 +1,35 @@ +package openapi + +import ( + "io/ioutil" + "net/http" + "time" +) + +func GetAvgFee() (string, error) { + url := "https://openapi.nkn.org/api/v1/statistics/avgtxfee" + client := http.Client{ + Timeout: time.Second * 10, // Timeout after 2 seconds + } + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return "", err + } + + res, getErr := client.Do(req) + if getErr != nil { + return "", getErr + } + + if res.Body != nil { + defer res.Body.Close() + } + + body, readErr := ioutil.ReadAll(res.Body) + if readErr != nil { + return "", readErr + } + result := string(body[:]) + return result, nil +} diff --git a/backend/topicmanager.go b/backend/topicmanager.go index ca161f8..179cced 100644 --- a/backend/topicmanager.go +++ b/backend/topicmanager.go @@ -8,14 +8,17 @@ import ( "github.com/rule110-io/surge/backend/constants" "github.com/rule110-io/surge/backend/models" "github.com/rule110-io/surge/backend/mutexes" + "github.com/wailsapp/wails/v2/pkg/runtime" ) var topicsMap map[string]models.Topic +var topicEncodedSubcribeStateMap map[string]int const topicsMapBucketKey = "topicBucket" func InitializeTopicsManager() { topicsMap = make(map[string]models.Topic) + topicEncodedSubcribeStateMap = make(map[string]int) //Load from db mapString, err := DbReadSetting(topicsMapBucketKey) @@ -28,7 +31,7 @@ func InitializeTopicsManager() { } } -func subscribeToSurgeTopic(topicName string, applySafeLock bool) { +func subscribeToSurgeTopic(topicName string, applySafeLock bool) (bool, error) { if applySafeLock { mutexes.TopicsMapLock.Lock() @@ -36,6 +39,10 @@ func subscribeToSurgeTopic(topicName string, applySafeLock bool) { } topicEncoded := TopicEncode(topicName) + subscriptionActive, err := IsSubscriptionActive(topicEncoded) + if err != nil { + return false, err + } if _, ok := topicsMap[topicName]; !ok { topicModel := models.Topic{ @@ -52,16 +59,40 @@ func subscribeToSurgeTopic(topicName string, applySafeLock bool) { DbWriteSetting(topicsMapBucketKey, mapString) } } - subscribeToPubSub(topicEncoded) - AnnounceFiles(topicEncoded) + + previousState := topicEncodedSubcribeStateMap[topicEncoded] + + subscribeSuccess := true + //If we dont have an active sub resubscribe. + if !subscriptionActive { + if !subscribeToPubSub(topicEncoded) { + subscribeSuccess = false + } + } else { + updateTopicSubscriptionState(topicEncoded, 2) + } + + //Only announce files if the client is first starting up, or when we are newly subscribed. + if subscribeSuccess { + if previousState == 0 || previousState == 1 { + AnnounceFiles(topicEncoded) + } + //first startup, were already subscribed, set the state. + updateTopicSubscriptionState(topicEncoded, 2) + } + + return subscribeSuccess, nil } -func unsubscribeFromSurgeTopic(topicName string) { +func unsubscribeFromSurgeTopic(topicName string) bool { mutexes.TopicsMapLock.Lock() defer mutexes.TopicsMapLock.Unlock() if topic, ok := topicsMap[topicName]; ok { - unsubscribeToPubSub(topic.NameEncoded) + unsubSuccess := unsubscribeToPubSub(topic.NameEncoded) + if !unsubSuccess { + return false + } } //Delete from map @@ -73,13 +104,26 @@ func unsubscribeFromSurgeTopic(topicName string) { mapString := string(mapBytes) DbWriteSetting(topicsMapBucketKey, mapString) } + + return true } func resubscribeToTopics() { mutexes.TopicsMapLock.Lock() defer mutexes.TopicsMapLock.Unlock() + for _, topic := range topicsMap { - subscribeToSurgeTopic(topic.Name, false) + _, err := subscribeToSurgeTopic(topic.Name, false) + if err != nil { + + //set all topics to pending state + pushError("Topic connection error", err.Error()) + for _, disableTopic := range topicsMap { + updateTopicSubscriptionState(disableTopic.NameEncoded, 1) + } + + break + } } } @@ -99,11 +143,20 @@ func GetTopicInfo(topicName string) models.TopicInfo { fileCount += bitSetVar } + state := 0 + + //get topic state + knownState, any := topicEncodedSubcribeStateMap[topicEncoded] + if any { + state = knownState + } + return models.TopicInfo{ - Name: topicName, - Subscribers: subCount, - FileCount: fileCount, - Permissions: GetTopicPermissions(topicName, GetAccountAddress()), + Name: topicName, + Subscribers: subCount, + FileCount: fileCount, + Permissions: GetTopicPermissions(topicName, GetAccountAddress()), + SubscriptionState: state, } } func GetTopicPermissions(topicName string, clientAddr string) models.TopicPermissions { @@ -144,12 +197,34 @@ func GetTopicsWithPermissions() []models.TopicInfo { modelData := []models.TopicInfo{} for _, v := range topicNames { + + state := 0 + //get topic state + knownState, any := topicEncodedSubcribeStateMap[TopicEncode(v)] + if any { + state = knownState + } + entry := models.TopicInfo{ - Name: v, - Permissions: GetTopicPermissions(v, GetAccountAddress()), + Name: v, + Permissions: GetTopicPermissions(v, GetAccountAddress()), + SubscriptionState: state, } modelData = append(modelData, entry) } return modelData } + +func updateTopicSubscriptionState(TopicEncoded string, NewState int) { + + previousValue, exists := topicEncodedSubcribeStateMap[TopicEncoded] + isChanged := !exists || previousValue != NewState + + if isChanged { + topicEncodedSubcribeStateMap[TopicEncoded] = NewState + if FrontendReady { + runtime.EventsEmit(*wailsContext, "topicsUpdated") + } + } +} diff --git a/backend/wallet.go b/backend/wallet.go new file mode 100644 index 0000000..0e7b71d --- /dev/null +++ b/backend/wallet.go @@ -0,0 +1,113 @@ +package surge + +import ( + "errors" + "fmt" + "log" + "strconv" + + nkn "github.com/nknorg/nkn-sdk-go" + "github.com/rule110-io/surge/backend/openapi" +) + +func WalletAddress() string { + wallet, _ := nkn.ClientAddrToWalletAddr(GetAccountAddress()) + return wallet +} + +func WalletTransfer(address string, amount string, fee string) (bool, string) { + config := &nkn.DefaultTransactionConfig + config.Fee = fee + + result, err := client.Transfer(address, amount, config) + if err != nil { + pushError("Transfer failed", err.Error()) + return false, "" + } + log.Println("Transfered " + amount + " nkn to " + address + " txHash: " + result) + return true, result +} + +func WalletBalance() string { + amount, err := client.Balance() + if err != nil { + pushError("Transfer failed", err.Error()) + return "-1" + } + return amount.String() +} + +func CalculateFee(Fee string) (string, error) { + avgFee, err := openapi.GetAvgFee() + if err != nil { + return "0.0", err + } + + avgFeeFloat, _ := strconv.ParseFloat(avgFee, 64) + + feePercent := 0.2 + lowFee := avgFeeFloat - avgFeeFloat*feePercent + highFee := avgFeeFloat + avgFeeFloat*feePercent + + switch Fee { + case "0": + return "0", nil + case "33": + return fmt.Sprintf("%f", lowFee), nil + case "66": + return avgFee, nil + case "100": + return fmt.Sprintf("%f", highFee), nil + } + + return "0", nil +} + +//ValidateBalanceForTransaction returns a boolean for whether there is enough balance to make a transation +func ValidateBalanceForTransaction(Amount float64, Fee float64, UtilTransaction bool) (bool, error) { + if !UtilTransaction && Amount < 0.00000001 { + return false, errors.New("minimum tip amount is 0.00000001") + } + + balance := WalletBalance() + balanceFloat, _ := strconv.ParseFloat(balance, 64) + + if Amount+Fee >= balanceFloat { + return false, errors.New("not enough nkn available required: " + fmt.Sprintf("%f", Amount+Fee) + " available: " + balance) + } + + return true, nil +} + +func IsSubscriptionActive(TopicEncoded string) (bool, error) { + subs, err := client.GetSubscribers(TopicEncoded, 0, 1000, false, true) + if err != nil { + return false, err + } + + for sub := range subs.Subscribers.Map { + if sub == GetAccountAddress() { + return true, nil + } + } + + for sub := range subs.SubscribersInTxPool.Map { + if sub == GetAccountAddress() { + return true, nil + } + } + return false, nil +} + +/*Wallet Features +- Import wallet from private key +- Export wallet private key +- ✔ Send transaction with (amount, fee, toAddress) +- ✔ WalletInfo (retrieve personal wallet address + wallet balance) +- ✔ Set/Get transaction fee default + + +- Optional: +seed + password wallet files instead of private keys? +get network average fee for last x amount of blocks +*/ diff --git a/backend/workers.go b/backend/workers.go index 54d7948..46bf85b 100644 --- a/backend/workers.go +++ b/backend/workers.go @@ -12,7 +12,6 @@ package surge import ( "time" - "github.com/rule110-io/surge/backend/constants" "github.com/rule110-io/surge/backend/models" "github.com/rule110-io/surge/backend/mutexes" "github.com/rule110-io/surge/backend/platform" @@ -25,7 +24,7 @@ func autoSubscribeWorker() { //As long as the client is running subscribe for { resubscribeToTopics() - time.Sleep(time.Second * 20 * constants.SubscriptionDuration) + time.Sleep(time.Second * 20) } } @@ -46,32 +45,28 @@ func updateFileDataWorker() { //Insert uploads allFiles := dbGetAllFiles() for _, file := range allFiles { + if file.IsHashing { + continue + } + if file.IsUploading { fileProgressMap[file.FileHash] = 1 } key := file.FileHash - //if file.IsPaused { - // continue - //} - if file.IsDownloading { numChunksLocal := chunksDownloaded(file.ChunkMap, file.NumChunks) progress := float32(float64(numChunksLocal) / float64(file.NumChunks)) fileProgressMap[file.FileHash] = progress if progress >= 1.0 { - platform.ShowNotification("Download Finished", "Download for "+file.FileName+" finished!") - pushNotification("Download Finished", file.FileName) file.IsDownloading = false - file.IsUploading = true - file.IsAvailable = true + file.IsUploading = false + file.IsAvailable = false + file.IsHashing = true dbInsertFile(file) - dbFile, err := dbGetFile(file.FileHash) - if err == nil { - AnnounceNewFile(dbFile) - } + go VerifyFile(file) } } @@ -108,3 +103,34 @@ func updateFileDataWorker() { zeroBandwidthMap["total"] = totalDown+totalUp == 0 } } + +func VerifyFile(file models.File) { + fileHash, err := HashFile(file.Path) + + if err != nil { + pushError("Download Failed", "File hash could not be verified.") + } else { + if file.FileHash == fileHash { + file.IsDownloading = false + file.IsHashing = false + file.IsUploading = true + file.IsAvailable = true + dbInsertFile(file) + + if err == nil { + AnnounceNewFile(&file) + } + platform.ShowNotification("Download Finished", "Download for "+file.FileName+" finished!") + pushNotification("Download Finished", file.FileName) + + } else { + pushError("Download Failed", "File hash does not match local file.") + file.IsDownloading = false + file.IsHashing = false + file.IsUploading = false + file.IsAvailable = false + file.IsMissing = true + dbInsertFile(file) + } + } +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1f6e602..3925d83 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "surge", - "version": "0.4.0-beta", + "version": "1.0.1-beta", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "surge", - "version": "0.4.0-beta", + "version": "1.0.1-beta", "dependencies": { "@download/blockies": "^1.0.3", "@taeuk-gang/chartjs-plugin-streaming": "^1.8.1", @@ -19,6 +19,7 @@ "feather-icons": "^4.28.0", "lodash": "^4.17.19", "regenerator-runtime": "^0.13.3", + "sass": "^1.53.0", "v-tooltip": "^2.0.3", "vue": "^2.6.11", "vue-bus": "^1.2.1", @@ -30,6 +31,7 @@ "vue-filter-pretty-bytes": "^0.1.5", "vue-lodash": "^2.1.2", "vue-moment": "^4.1.0", + "vue-notification": "^1.3.20", "vue-router": "^3.3.4", "vue-slider-component": "^3.2.15", "vue-tour": "^1.5.0", @@ -43,7 +45,6 @@ "eslint": "^6.8.0", "eslint-plugin-vue": "^6.2.1", "eventsource-polyfill": "^0.9.6", - "node-sass": "^6.0.1", "prerender-spa-plugin": "^3.4.0", "sass-loader": "^10.1.0", "vue-svg-loader": "^0.16.0", @@ -2730,7 +2731,9 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/accepts": { "version": "1.3.7", @@ -2841,6 +2844,8 @@ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.4.2" } @@ -2912,7 +2917,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2952,6 +2956,8 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -3034,6 +3040,8 @@ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -3118,9 +3126,9 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, "dependencies": { "lodash": "^4.17.14" @@ -3137,6 +3145,8 @@ "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "*" } @@ -3402,8 +3412,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "optional": true, "engines": { "node": ">=8" } @@ -3896,6 +3904,8 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", @@ -3913,6 +3923,8 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -4010,8 +4022,6 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "optional": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4032,8 +4042,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "optional": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -4045,8 +4053,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4058,8 +4064,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "optional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4071,8 +4075,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "optional": true, "engines": { "node": ">=0.12.0" } @@ -4081,8 +4083,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "optional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -4470,6 +4470,8 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -4525,6 +4527,17 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -4654,7 +4667,9 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/consolidate": { "version": "0.15.1", @@ -5385,6 +5400,8 @@ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", "dev": true, + "optional": true, + "peer": true, "dependencies": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" @@ -5398,6 +5415,8 @@ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5678,7 +5697,9 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/depd": { "version": "1.1.2", @@ -6032,6 +6053,8 @@ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -7104,9 +7127,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "funding": [ { "type": "individual", @@ -7213,6 +7236,8 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -7242,7 +7267,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -7269,6 +7293,8 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, + "optional": true, + "peer": true, "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -7285,6 +7311,8 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -7294,6 +7322,8 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, + "peer": true, "dependencies": { "number-is-nan": "^1.0.0" }, @@ -7306,6 +7336,8 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, + "peer": true, "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7320,6 +7352,8 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^2.0.0" }, @@ -7332,6 +7366,8 @@ "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "globule": "^1.0.0" }, @@ -7376,6 +7412,8 @@ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -7507,6 +7545,8 @@ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "~7.1.1", "lodash": "~4.17.10", @@ -7521,6 +7561,8 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7597,6 +7639,8 @@ "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -7613,27 +7657,6 @@ "node": ">= 0.4.0" } }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", @@ -7683,7 +7706,9 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/has-value": { "version": "1.0.0", @@ -7836,6 +7861,8 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -7848,6 +7875,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -7859,7 +7888,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/hpack.js": { "version": "2.1.6", @@ -8234,6 +8265,11 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==" + }, "node_modules/import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", @@ -8359,6 +8395,8 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -8646,8 +8684,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -8808,7 +8844,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8826,7 +8861,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -9097,7 +9131,9 @@ "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/js-message": { "version": "1.0.7", @@ -9539,6 +9575,8 @@ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" }, @@ -9599,6 +9637,8 @@ "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", @@ -9625,6 +9665,8 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=10" }, @@ -9770,6 +9812,8 @@ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=4" } @@ -9831,9 +9875,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/minimist-options": { @@ -9841,6 +9885,8 @@ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", @@ -9855,6 +9901,8 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -9882,6 +9930,8 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -9894,7 +9944,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/mississippi": { "version": "3.0.0", @@ -9943,9 +9995,9 @@ } }, "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "engines": { "node": "*" } @@ -10010,7 +10062,8 @@ "version": "2.15.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "dev": true + "dev": true, + "optional": true }, "node_modules/nanomatch": { "version": "1.2.13", @@ -10084,6 +10137,8 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -10108,6 +10163,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -10120,6 +10177,8 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -10135,6 +10194,8 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -10150,6 +10211,8 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -10164,7 +10227,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/node-ipc": { "version": "9.2.1", @@ -10224,14 +10289,16 @@ "dev": true }, "node_modules/node-sass": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz", - "integrity": "sha512-f+Rbqt92Ful9gX0cGtdYwjTrWAaGURgaK5rZCWOgCNyGWusFYHhbqCCBoFBeat+HKETOU02AyTxNhJV0YZf2jQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.0.tgz", + "integrity": "sha512-6yUnsD3L8fVbgMX6nKQqZkjRcG7a/PpmF0pEyeWf+BgbTj2ToJlCYrnUifL2KbjV5gIY22I3oppahBWA3B+jUg==", "dev": true, "hasInstallScript": true, + "optional": true, + "peer": true, "dependencies": { "async-foreach": "^0.1.3", - "chalk": "^1.1.1", + "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "gaze": "^1.0.0", "get-stdin": "^4.0.1", @@ -10240,7 +10307,7 @@ "meow": "^9.0.0", "nan": "^2.13.2", "node-gyp": "^7.1.0", - "npmlog": "^4.0.0", + "npmlog": "^5.0.0", "request": "^2.88.0", "sass-graph": "2.2.5", "stdout-stream": "^1.4.0", @@ -10254,37 +10321,78 @@ } }, "node_modules/node-sass/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "optional": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/node-sass/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/node-sass/node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, "node_modules/node-sass/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/node-sass/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/node-sass/node_modules/cross-spawn": { @@ -10292,6 +10400,8 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -10301,20 +10411,98 @@ "node": ">= 8" } }, + "node_modules/node-sass/node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-sass/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-sass/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-sass/node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/node-sass/node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } }, + "node_modules/node-sass/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/node-sass/node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -10327,38 +10515,65 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } }, - "node_modules/node-sass/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "node_modules/node-sass/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "ansi-regex": "^2.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/node-sass/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "node_modules/node-sass/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=0.8.0" + "node": ">=8" } }, - "node_modules/node-sass/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" + "node_modules/node-sass/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-sass/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" @@ -10372,6 +10587,8 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "abbrev": "1" }, @@ -10387,6 +10604,8 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", @@ -10402,6 +10621,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -10414,6 +10635,8 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -10428,13 +10651,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -10480,6 +10704,8 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -10510,6 +10736,8 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -11236,7 +11464,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -12268,6 +12495,8 @@ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -12335,6 +12564,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", @@ -12352,6 +12583,8 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -12429,8 +12662,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "optional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -12443,6 +12674,8 @@ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" @@ -12856,11 +13089,29 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/sass": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.53.0.tgz", + "integrity": "sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/sass-graph": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "^7.0.0", "lodash": "^4.0.0", @@ -12876,6 +13127,8 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -12885,6 +13138,8 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -12895,13 +13150,17 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/sass-graph/node_modules/find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "locate-path": "^3.0.0" }, @@ -12914,6 +13173,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -12927,6 +13188,8 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "p-limit": "^2.0.0" }, @@ -12939,6 +13202,8 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=4" } @@ -12948,6 +13213,8 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -12962,6 +13229,8 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -12976,6 +13245,8 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "cliui": "^5.0.0", "find-up": "^3.0.0", @@ -12994,6 +13265,8 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -13130,6 +13403,8 @@ "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", "dev": true, + "optional": true, + "peer": true, "dependencies": { "js-base64": "^2.1.8", "source-map": "^0.4.2" @@ -13140,6 +13415,8 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, + "optional": true, + "peer": true, "dependencies": { "amdefine": ">=0.0.4" }, @@ -13727,6 +14004,14 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -14018,6 +14303,8 @@ "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "readable-stream": "^2.0.1" } @@ -14174,6 +14461,8 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "min-indent": "^1.0.0" }, @@ -14387,6 +14676,8 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -14404,6 +14695,8 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=10" } @@ -14413,6 +14706,8 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "optional": true, + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -14424,7 +14719,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/terser": { "version": "4.8.0", @@ -14808,6 +15105,8 @@ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -14817,6 +15116,8 @@ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.2" } @@ -15192,9 +15493,9 @@ } }, "node_modules/url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, "dependencies": { "querystringify": "^2.1.1", @@ -15602,6 +15903,14 @@ "vue": ">=1.x.x" } }, + "node_modules/vue-notification": { + "version": "1.3.20", + "resolved": "https://registry.npmjs.org/vue-notification/-/vue-notification-1.3.20.tgz", + "integrity": "sha512-vPj67Ah72p8xvtyVE8emfadqVWguOScAjt6OJDEUdcW5hW189NsqvfkOrctxHUUO9UYl9cTbIkzAEcPnHu+zBQ==", + "peerDependencies": { + "vue": "^2.0.0" + } + }, "node_modules/vue-property-decorator": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-8.5.1.tgz", @@ -16560,6 +16869,8 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -18997,7 +19308,9 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "accepts": { "version": "1.3.7", @@ -19079,7 +19392,9 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "ansi-colors": { "version": "3.2.4", @@ -19127,7 +19442,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -19150,6 +19464,8 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "dev": true, + "optional": true, + "peer": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -19213,7 +19529,9 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "asn1": { "version": "0.2.6", @@ -19290,9 +19608,9 @@ "dev": true }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, "requires": { "lodash": "^4.17.14" @@ -19308,7 +19626,9 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "async-limiter": { "version": "1.0.1", @@ -19507,9 +19827,7 @@ "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "optional": true + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "bindings": { "version": "1.5.0", @@ -19939,6 +20257,8 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, + "optional": true, + "peer": true, "requires": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", @@ -19949,7 +20269,9 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -20036,8 +20358,6 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "optional": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -20053,8 +20373,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "optional": true, "requires": { "fill-range": "^7.0.1" } @@ -20063,8 +20381,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "optional": true, "requires": { "to-regex-range": "^5.0.1" } @@ -20073,8 +20389,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "optional": true, "requires": { "is-glob": "^4.0.1" } @@ -20082,16 +20396,12 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "optional": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "optional": true, "requires": { "is-number": "^7.0.0" } @@ -20395,7 +20705,9 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "collection-visit": { "version": "1.0.0", @@ -20447,6 +20759,14 @@ "simple-swizzle": "^0.2.2" } }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "optional": true, + "peer": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -20560,7 +20880,9 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "consolidate": { "version": "0.15.1", @@ -21141,6 +21463,8 @@ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", "dev": true, + "optional": true, + "peer": true, "requires": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" @@ -21150,7 +21474,9 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -21367,7 +21693,9 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "depd": { "version": "1.1.2", @@ -21667,7 +21995,9 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "errno": { "version": "0.1.8", @@ -22538,9 +22868,9 @@ } }, "follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "for-in": { "version": "1.0.2", @@ -22612,6 +22942,8 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "optional": true, + "peer": true, "requires": { "minipass": "^3.0.0" } @@ -22638,7 +22970,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true }, "function-bind": { @@ -22658,6 +22989,8 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, + "optional": true, + "peer": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -22673,13 +23006,17 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, + "peer": true, "requires": { "number-is-nan": "^1.0.0" } @@ -22689,6 +23026,8 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, + "peer": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -22700,6 +23039,8 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, + "peer": true, "requires": { "ansi-regex": "^2.0.0" } @@ -22711,6 +23052,8 @@ "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "dev": true, + "optional": true, + "peer": true, "requires": { "globule": "^1.0.0" } @@ -22742,7 +23085,9 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "get-stream": { "version": "4.1.0", @@ -22846,6 +23191,8 @@ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", "dev": true, + "optional": true, + "peer": true, "requires": { "glob": "~7.1.1", "lodash": "~4.17.10", @@ -22857,6 +23204,8 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -22918,7 +23267,9 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "has": { "version": "1.0.3", @@ -22929,23 +23280,6 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - } - } - }, "has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", @@ -22977,7 +23311,9 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "has-value": { "version": "1.0.0", @@ -23096,6 +23432,8 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "dev": true, + "optional": true, + "peer": true, "requires": { "lru-cache": "^6.0.0" }, @@ -23105,6 +23443,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "optional": true, + "peer": true, "requires": { "yallist": "^4.0.0" } @@ -23113,7 +23453,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -23409,6 +23751,11 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==" + }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", @@ -23502,7 +23849,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "indexes-of": { "version": "1.0.1", @@ -23725,8 +24074,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, "requires": { "binary-extensions": "^2.0.0" } @@ -23838,8 +24185,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -23851,7 +24197,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -24046,7 +24391,9 @@ "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "js-message": { "version": "1.0.7", @@ -24412,7 +24759,9 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "map-visit": { "version": "1.0.0", @@ -24461,6 +24810,8 @@ "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", @@ -24480,7 +24831,9 @@ "version": "0.18.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -24595,7 +24948,9 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "mini-css-extract-plugin": { "version": "0.9.0", @@ -24644,9 +24999,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "minimist-options": { @@ -24654,6 +25009,8 @@ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, + "optional": true, + "peer": true, "requires": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", @@ -24664,7 +25021,9 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -24690,6 +25049,8 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, + "optional": true, + "peer": true, "requires": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -24699,7 +25060,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -24741,9 +25104,9 @@ } }, "moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "move-concurrently": { "version": "1.0.1", @@ -24802,7 +25165,8 @@ "version": "2.15.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "dev": true + "dev": true, + "optional": true }, "nanomatch": { "version": "1.2.13", @@ -24867,6 +25231,8 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -24885,6 +25251,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "optional": true, + "peer": true, "requires": { "yallist": "^4.0.0" } @@ -24894,6 +25262,8 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, + "optional": true, + "peer": true, "requires": { "glob": "^7.1.3" } @@ -24903,6 +25273,8 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "lru-cache": "^6.0.0" } @@ -24912,6 +25284,8 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "optional": true, + "peer": true, "requires": { "isexe": "^2.0.0" } @@ -24920,7 +25294,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -24981,13 +25357,14 @@ "dev": true }, "node-sass": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz", - "integrity": "sha512-f+Rbqt92Ful9gX0cGtdYwjTrWAaGURgaK5rZCWOgCNyGWusFYHhbqCCBoFBeat+HKETOU02AyTxNhJV0YZf2jQ==", + "version": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.0.tgz", + "integrity": "sha512-6yUnsD3L8fVbgMX6nKQqZkjRcG7a/PpmF0pEyeWf+BgbTj2ToJlCYrnUifL2KbjV5gIY22I3oppahBWA3B+jUg==", "dev": true, + "optional": true, + "peer": true, "requires": { "async-foreach": "^0.1.3", - "chalk": "^1.1.1", + "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "gaze": "^1.0.0", "get-stdin": "^4.0.1", @@ -24996,7 +25373,7 @@ "meow": "^9.0.0", "nan": "^2.13.2", "node-gyp": "^7.1.0", - "npmlog": "^4.0.0", + "npmlog": "^5.0.0", "request": "^2.88.0", "sass-graph": "2.2.5", "stdout-stream": "^1.4.0", @@ -25004,28 +25381,57 @@ }, "dependencies": { "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "optional": true, + "peer": true }, "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } }, "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "optional": true, + "peer": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "color-name": "~1.1.4" } }, "cross-spawn": { @@ -25033,23 +25439,91 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "optional": true, + "peer": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true, + "peer": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "optional": true, + "peer": true + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "dev": true, + "optional": true, + "peer": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "optional": true, + "peer": true, "requires": { "shebang-regex": "^3.0.0" } @@ -25058,28 +25532,52 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "dev": true, + "optional": true, + "peer": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "optional": true, + "peer": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.1" } }, "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "optional": true, + "peer": true, "requires": { "isexe": "^2.0.0" } @@ -25091,6 +25589,8 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "abbrev": "1" } @@ -25100,6 +25600,8 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, + "optional": true, + "peer": true, "requires": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", @@ -25112,6 +25614,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "optional": true, + "peer": true, "requires": { "yallist": "^4.0.0" } @@ -25121,6 +25625,8 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "lru-cache": "^6.0.0" } @@ -25129,15 +25635,16 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-range": { "version": "0.1.2", @@ -25171,6 +25678,8 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, + "optional": true, + "peer": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -25197,7 +25706,9 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "oauth-sign": { "version": "0.9.0", @@ -25768,8 +26279,7 @@ "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, "pify": { "version": "4.0.1", @@ -26646,7 +27156,9 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "randombytes": { "version": "2.1.0", @@ -26746,6 +27258,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, + "optional": true, + "peer": true, "requires": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", @@ -26756,7 +27270,9 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -26779,8 +27295,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "optional": true, "requires": { "picomatch": "^2.2.1" } @@ -26790,6 +27304,8 @@ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, + "optional": true, + "peer": true, "requires": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" @@ -27129,11 +27645,23 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sass": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.53.0.tgz", + "integrity": "sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==", + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, "sass-graph": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", "dev": true, + "optional": true, + "peer": true, "requires": { "glob": "^7.0.0", "lodash": "^4.0.0", @@ -27145,13 +27673,17 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, + "optional": true, + "peer": true, "requires": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -27162,13 +27694,17 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, + "optional": true, + "peer": true, "requires": { "locate-path": "^3.0.0" } @@ -27178,6 +27714,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, + "optional": true, + "peer": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -27188,6 +27726,8 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "p-limit": "^2.0.0" } @@ -27196,13 +27736,17 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, + "optional": true, + "peer": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -27214,6 +27758,8 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, + "optional": true, + "peer": true, "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -27225,6 +27771,8 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, + "optional": true, + "peer": true, "requires": { "cliui": "^5.0.0", "find-up": "^3.0.0", @@ -27243,6 +27791,8 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, + "optional": true, + "peer": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -27333,6 +27883,8 @@ "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", "dev": true, + "optional": true, + "peer": true, "requires": { "js-base64": "^2.1.8", "source-map": "^0.4.2" @@ -27343,6 +27895,8 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, + "optional": true, + "peer": true, "requires": { "amdefine": ">=0.0.4" } @@ -27854,6 +28408,11 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, "source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -28105,6 +28664,8 @@ "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "dev": true, + "optional": true, + "peer": true, "requires": { "readable-stream": "^2.0.1" } @@ -28236,6 +28797,8 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "min-indent": "^1.0.0" } @@ -28414,6 +28977,8 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, + "optional": true, + "peer": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -28427,19 +28992,25 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -28746,13 +29317,17 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "true-case-path": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "dev": true, + "optional": true, + "peer": true, "requires": { "glob": "^7.1.2" } @@ -29056,9 +29631,9 @@ } }, "url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, "requires": { "querystringify": "^2.1.1", @@ -29376,6 +29951,12 @@ "moment": "^2.19.2" } }, + "vue-notification": { + "version": "1.3.20", + "resolved": "https://registry.npmjs.org/vue-notification/-/vue-notification-1.3.20.tgz", + "integrity": "sha512-vPj67Ah72p8xvtyVE8emfadqVWguOScAjt6OJDEUdcW5hW189NsqvfkOrctxHUUO9UYl9cTbIkzAEcPnHu+zBQ==", + "requires": {} + }, "vue-property-decorator": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-8.5.1.tgz", @@ -30159,6 +30740,8 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, + "optional": true, + "peer": true, "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" } diff --git a/frontend/package.json b/frontend/package.json index 72533cc..938a7b5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,6 +20,7 @@ "feather-icons": "^4.28.0", "lodash": "^4.17.19", "regenerator-runtime": "^0.13.3", + "sass": "^1.53.0", "v-tooltip": "^2.0.3", "vue": "^2.6.11", "vue-bus": "^1.2.1", @@ -31,6 +32,7 @@ "vue-filter-pretty-bytes": "^0.1.5", "vue-lodash": "^2.1.2", "vue-moment": "^4.1.0", + "vue-notification": "^1.3.20", "vue-router": "^3.3.4", "vue-slider-component": "^3.2.15", "vue-tour": "^1.5.0", @@ -44,7 +46,6 @@ "eslint": "^6.8.0", "eslint-plugin-vue": "^6.2.1", "eventsource-polyfill": "^0.9.6", - "node-sass": "^6.0.1", "prerender-spa-plugin": "^3.4.0", "sass-loader": "^10.1.0", "vue-svg-loader": "^0.16.0", @@ -77,4 +78,4 @@ "last 2 versions", "not ie <= 8" ] -} \ No newline at end of file +} diff --git a/frontend/src/assets/icons/DropdownIcon.svg b/frontend/src/assets/icons/DropdownIcon.svg new file mode 100644 index 0000000..4ca1022 --- /dev/null +++ b/frontend/src/assets/icons/DropdownIcon.svg @@ -0,0 +1,3 @@ + diff --git a/frontend/src/assets/icons/TipIcon.svg b/frontend/src/assets/icons/TipIcon.svg new file mode 100644 index 0000000..1cc56ca --- /dev/null +++ b/frontend/src/assets/icons/TipIcon.svg @@ -0,0 +1,8 @@ + diff --git a/frontend/src/assets/icons/WalletIcon.svg b/frontend/src/assets/icons/WalletIcon.svg new file mode 100644 index 0000000..26e5414 --- /dev/null +++ b/frontend/src/assets/icons/WalletIcon.svg @@ -0,0 +1,11 @@ + diff --git a/frontend/src/assets/scss/_main.scss b/frontend/src/assets/scss/_main.scss index b21666a..dc1944d 100644 --- a/frontend/src/assets/scss/_main.scss +++ b/frontend/src/assets/scss/_main.scss @@ -61,6 +61,30 @@ a { } .text { + &_descr { + font-family: Inter; + font-style: normal; + font-weight: 400; + font-size: 0.8125rem; + line-height: 16px; + color: #7b7d82; + } + + &_link { + color: $primary; + text-decoration: underline; + transition: $transition-1; + cursor: pointer; + + &:hover { + color: white; + } + } + + &_select { + user-select: text; + } + &_wrap { &_none { overflow: hidden; @@ -109,7 +133,6 @@ a { } ::-webkit-scrollbar-track { - box-shadow: inset 0 0 6px $white-ghost; border-radius: $br-md; transition: $transition-1; } @@ -292,7 +315,12 @@ th { .table { &__row { &_active { - background: linear-gradient(0deg, rgba(10, 151, 149, 0.2), rgba(10, 151, 149, 0.2)), #131416; + background: linear-gradient( + 0deg, + rgba(10, 151, 149, 0.2), + rgba(10, 151, 149, 0.2) + ), + #131416; background-blend-mode: normal; td { diff --git a/frontend/src/assets/scss/_variables.scss b/frontend/src/assets/scss/_variables.scss index 066ca1c..5557bf2 100644 --- a/frontend/src/assets/scss/_variables.scss +++ b/frontend/src/assets/scss/_variables.scss @@ -29,6 +29,7 @@ $grey-light: #7e8084; $grey-dark: #28282d; $red: #eb5757; $danger: #ff3d48; +$warning: #ffce6d; $success: #48ff9c; $black-light: rgba(255, 255, 255, 0.03); $text-white: rgba(255, 255, 255, 0.8); @@ -103,4 +104,4 @@ $border: 1px solid $semi-dark; $border-transparent: 1px solid rgba(225, 225, 225, 0.1); $border-primary: 1px solid rgba(255, 255, 255, 0.07); -$sidebar-width: 224px; +$sidebar-width: 234px; diff --git a/frontend/src/components/Controls/Input/Input.scss b/frontend/src/components/Controls/Input/Input.scss index 6970375..69a9c8d 100644 --- a/frontend/src/components/Controls/Input/Input.scss +++ b/frontend/src/components/Controls/Input/Input.scss @@ -79,6 +79,28 @@ } } + &__after { + position: absolute; + right: 16px; + top: 9px; + padding-left: 16px; + font-weight: 500; + min-width: 30px; + text-align: center; + color: $grey; + + &::before { + content: ""; + display: block; + width: 2px; + position: absolute; + top: -8px; + left: 0; + height: 34px; + background: #323232; + } + } + &__icon { position: relative; height: 24px; diff --git a/frontend/src/components/Controls/Input/Input.vue b/frontend/src/components/Controls/Input/Input.vue index 2d8d75f..f92a573 100644 --- a/frontend/src/components/Controls/Input/Input.vue +++ b/frontend/src/components/Controls/Input/Input.vue @@ -15,6 +15,7 @@ :class="[ icon ? 'input__controller_icon' : null, `input__controller_theme_${theme}`, + after ? 'input__controller_after' : null, ]" :type="type" :placeholder="placeholder" @@ -23,6 +24,7 @@ @focus="focus = true" @blur="focus = false" /> +