├── .babelrc ├── .gitignore ├── LICENSE.txt ├── README.md ├── controller.go ├── cron.go ├── job.go ├── package.json ├── qor_job.go ├── queue.go ├── queue └── kubernetes │ ├── README.md │ └── kubernetes.go ├── scheduler.go ├── views └── themes │ └── worker │ ├── actions │ └── index │ │ └── 5.scope.tmpl │ ├── assets │ ├── javascripts │ │ ├── worker.js │ │ └── worker │ │ │ └── workers.js │ └── stylesheets │ │ ├── worker.css │ │ └── worker │ │ └── app.scss │ ├── edit.tmpl │ └── new.tmpl ├── worker.go └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Back end 2 | Gemfile.lock 3 | gin-bin 4 | .DS_Store 5 | tmp 6 | worker_data 7 | *.exe 8 | /test/integration/integration 9 | /test/integration/public 10 | 11 | # Example 12 | /example/example 13 | /example/public 14 | /example/harp.json 15 | 16 | /admin/public/ 17 | 18 | # Front end 19 | bower_components 20 | node_modules 21 | __* 22 | *.css.map 23 | *.js.map 24 | *.min.map 25 | .sass-cache 26 | npm-debug.log 27 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) The Plant https://theplant.jp 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Worker 2 | 3 | Worker runs a single [*Job*]() in the background, it can do so immediately or at a scheduled time. 4 | 5 | Once registered with [QOR Admin](http://github.com/qor/admin), [Worker](https://github.com/qor/worker) will provide a `Workers` section in the navigation tree, containing pages for listing and managing the following aspects of Workers: 6 | 7 | - All *Jobs*. 8 | - Running: *Jobs* that are currently running. 9 | - Scheduled: *Jobs* which have been scheduled to run at a time in the future. 10 | - Done: finished *Jobs*. 11 | - Errors: any errors output from any Workers that have been run. 12 | 13 | The admin interface for a schedulable *Job* will have an additional `Schedule Time` input, with which administrators can set the scheduled date and time. 14 | 15 | [![GoDoc](https://godoc.org/github.com/qor/worker?status.svg)](https://godoc.org/github.com/qor/worker) 16 | 17 | ## Usage 18 | 19 | ```go 20 | import "github.com/qor/worker" 21 | 22 | func main() { 23 | // Define Worker 24 | Worker := worker.New() 25 | 26 | // Arguments used to run a job 27 | type sendNewsletterArgument struct { 28 | Subject string 29 | Content string `sql:"size:65532"` 30 | SendPassword string 31 | 32 | // If job's argument has `worker.Schedule` embedded, it will get run at a scheduled time 33 | worker.Schedule 34 | } 35 | 36 | // Register Job 37 | Worker.RegisterJob(&worker.Job{ 38 | Name: "Send Newsletter", // Registerd Job Name 39 | Handler: func(argument interface{}, qorJob worker.QorJobInterface) error { 40 | // `AddLog` add job log 41 | qorJob.AddLog("Started sending newsletters...") 42 | qorJob.AddLog(fmt.Sprintf("Argument: %+v", argument.(*sendNewsletterArgument))) 43 | 44 | for i := 1; i <= 100; i++ { 45 | time.Sleep(100 * time.Millisecond) 46 | qorJob.AddLog(fmt.Sprintf("Sending newsletter %v...", i)) 47 | // `SetProgress` set job progress percent, from 0 - 100 48 | qorJob.SetProgress(uint(i)) 49 | } 50 | 51 | qorJob.AddLog("Finished send newsletters") 52 | return nil 53 | }, 54 | // Arguments used to run a job 55 | Resource: Admin.NewResource(&sendNewsletterArgument{}), 56 | }) 57 | 58 | // Add Worker to qor admin, so you could manage jobs in the admin interface 59 | Admin.AddResource(Worker) 60 | } 61 | ``` 62 | 63 | ## Things to note 64 | 65 | - If a *Job* is scheduled within 2 minutes of the current time, then it will be run immediately. 66 | - It is possible, via the admin interface, to abort a currently running *Job*: view the *Job*'s data via `Workers > Running` or `Workers > All Jobs` and press the `Abort running Job` button. 67 | - It is possible, via the admin interface, to abort a scheduled *Job*: view the *Job*'s data via `Workers > Scheduled` or `Workers > All Jobs` and press the `Cancel scheduled Job` button. 68 | - It is possible, via the admin interface, to update a scheduled *Job*, including setting a new date and time: view the *Job*'s data via `Workers > Scheduled` or `Workers > All Jobs`, update the `Schedule Time` field's value, and press the `Update scheduled Job` button. Please be aware that scheduling a *Job* to a date/time in the past will see the Job get run immediately. 69 | 70 | [Worker Demo: http://demo.getqor.com/admin/workers](http://demo.getqor.com/admin/workers) 71 | 72 | ## License 73 | 74 | Released under the [MIT License](http://opensource.org/licenses/MIT). 75 | -------------------------------------------------------------------------------- /controller.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "errors" 5 | "html/template" 6 | "net/http" 7 | 8 | "github.com/qor/admin" 9 | "github.com/qor/responder" 10 | "github.com/qor/roles" 11 | ) 12 | 13 | type workerController struct { 14 | *Worker 15 | } 16 | 17 | func (wc workerController) Index(context *admin.Context) { 18 | context = context.NewResourceContext(wc.JobResource) 19 | result, err := context.FindMany() 20 | context.AddError(err) 21 | 22 | if context.HasError() { 23 | http.NotFound(context.Writer, context.Request) 24 | } else { 25 | responder.With("html", func() { 26 | context.Execute("index", result) 27 | }).With("json", func() { 28 | context.JSON("index", result) 29 | }).Respond(context.Request) 30 | } 31 | } 32 | 33 | func (wc workerController) Show(context *admin.Context) { 34 | job, err := wc.GetJob(context.ResourceID) 35 | context.AddError(err) 36 | context.Execute("show", job) 37 | } 38 | 39 | func (wc workerController) New(context *admin.Context) { 40 | context.Execute("new", wc.Worker) 41 | } 42 | 43 | func (wc workerController) Update(context *admin.Context) { 44 | if job, err := wc.GetJob(context.ResourceID); err == nil { 45 | if job.GetStatus() == JobStatusScheduled || job.GetStatus() == JobStatusNew { 46 | if job.GetJob().HasPermission(roles.Update, context.Context) { 47 | if context.AddError(wc.Worker.JobResource.Decode(context.Context, job)); !context.HasError() { 48 | context.AddError(wc.Worker.JobResource.CallSave(job, context.Context)) 49 | context.AddError(wc.Worker.AddJob(job)) 50 | } 51 | 52 | if !context.HasError() { 53 | context.Flash(string(context.Admin.T(context.Context, "qor_worker.form.successfully_updated", "{{.Name}} was successfully updated", wc.Worker.JobResource)), "success") 54 | } 55 | 56 | context.Execute("edit", job) 57 | return 58 | } 59 | } 60 | 61 | context.AddError(errors.New("not allowed to update this job")) 62 | } else { 63 | context.AddError(err) 64 | } 65 | 66 | http.Redirect(context.Writer, context.Request, context.Request.URL.Path, http.StatusFound) 67 | } 68 | 69 | func (wc workerController) AddJob(context *admin.Context) { 70 | jobResource := wc.Worker.JobResource 71 | result := jobResource.NewStruct().(QorJobInterface) 72 | job := wc.Worker.GetRegisteredJob(context.Request.Form.Get("job_name")) 73 | result.SetJob(job) 74 | 75 | if !job.HasPermission(roles.Create, context.Context) { 76 | context.AddError(errors.New("don't have permission to run job")) 77 | } 78 | 79 | if context.AddError(jobResource.Decode(context.Context, result)); !context.HasError() { 80 | // ensure job name is correct 81 | result.SetJob(job) 82 | context.AddError(jobResource.CallSave(result, context.Context)) 83 | context.AddError(wc.Worker.AddJob(result)) 84 | } 85 | 86 | if context.HasError() { 87 | responder.With("html", func() { 88 | context.Writer.WriteHeader(422) 89 | context.Execute("edit", result) 90 | }).With("json", func() { 91 | context.Writer.WriteHeader(422) 92 | context.JSON("index", map[string]interface{}{"errors": context.GetErrors()}) 93 | }).Respond(context.Request) 94 | return 95 | } 96 | 97 | context.Flash(string(context.Admin.T(context.Context, "qor_worker.form.successfully_created", "{{.Name}} was successfully created", jobResource)), "success") 98 | http.Redirect(context.Writer, context.Request, context.Request.URL.Path, http.StatusFound) 99 | } 100 | 101 | func (wc workerController) RunJob(context *admin.Context) { 102 | if newJob := wc.Worker.saveAnotherJob(context.ResourceID); newJob != nil { 103 | wc.Worker.AddJob(newJob) 104 | } else { 105 | context.AddError(errors.New("failed to clone job " + context.ResourceID)) 106 | } 107 | 108 | http.Redirect(context.Writer, context.Request, context.URLFor(wc.Worker.JobResource), http.StatusFound) 109 | } 110 | 111 | func (wc workerController) KillJob(context *admin.Context) { 112 | var msg template.HTML 113 | qorJob, err := wc.Worker.GetJob(context.ResourceID) 114 | 115 | if err == nil { 116 | if err = wc.Worker.KillJob(qorJob.GetJobID()); err == nil { 117 | msg = context.Admin.T(context.Context, "qor_worker.form.successfully_killed", "{{.Name}} was successfully killed", wc.JobResource) 118 | } else { 119 | msg = context.Admin.T(context.Context, "qor_worker.form.failed_to_kill", "Failed to kill job {{.Name}}", wc.JobResource) 120 | } 121 | } 122 | 123 | if err == nil { 124 | responder.With("html", func() { 125 | context.Flash(string(msg), "success") 126 | http.Redirect(context.Writer, context.Request, context.Request.URL.Path, http.StatusFound) 127 | }).With("json", func() { 128 | context.JSON("ok", map[string]interface{}{"message": msg}) 129 | }).Respond(context.Request) 130 | } else { 131 | responder.With("html", func() { 132 | context.Flash(string(msg), "error") 133 | http.Redirect(context.Writer, context.Request, context.Request.URL.Path, http.StatusFound) 134 | }).With("json", func() { 135 | context.Writer.WriteHeader(422) 136 | context.JSON("index", map[string]interface{}{"errors": []error{err}}) 137 | }) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /cron.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "os" 8 | "os/exec" 9 | "os/signal" 10 | "path/filepath" 11 | "reflect" 12 | "strings" 13 | "sync" 14 | "syscall" 15 | "time" 16 | ) 17 | 18 | type cronJob struct { 19 | JobID string 20 | Pid int 21 | Command string 22 | Delete bool `json:"-"` 23 | } 24 | 25 | func (job cronJob) ToString() string { 26 | marshal, _ := json.Marshal(job) 27 | return fmt.Sprintf("## BEGIN QOR JOB %v # %v\n%v\n## END QOR JOB\n", job.JobID, string(marshal), job.Command) 28 | } 29 | 30 | // Cron implemented a worker Queue based on cronjob 31 | type Cron struct { 32 | Jobs []*cronJob 33 | CronJobs []string 34 | mutex sync.Mutex `sql:"-"` 35 | } 36 | 37 | // NewCronQueue initialize a Cron queue 38 | func NewCronQueue() *Cron { 39 | return &Cron{} 40 | } 41 | 42 | func (cron *Cron) parseJobs() []*cronJob { 43 | cron.mutex.Lock() 44 | 45 | cron.Jobs = []*cronJob{} 46 | cron.CronJobs = []string{} 47 | if out, err := exec.Command("crontab", "-l").Output(); err == nil { 48 | var inQorJob bool 49 | for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { 50 | if strings.HasPrefix(line, "## BEGIN QOR JOB") { 51 | inQorJob = true 52 | if idx := strings.Index(line, "{"); idx > 1 { 53 | var job cronJob 54 | if json.Unmarshal([]byte(line[idx-1:]), &job) == nil { 55 | cron.Jobs = append(cron.Jobs, &job) 56 | } 57 | } 58 | } 59 | 60 | if !inQorJob { 61 | cron.CronJobs = append(cron.CronJobs, line) 62 | } 63 | 64 | if strings.HasPrefix(line, "## END QOR JOB") { 65 | inQorJob = false 66 | } 67 | } 68 | } 69 | return cron.Jobs 70 | } 71 | 72 | func (cron *Cron) writeCronJob() error { 73 | defer cron.mutex.Unlock() 74 | 75 | cmd := exec.Command("crontab", "-") 76 | cmd.Stdout = os.Stdout 77 | cmd.Stderr = os.Stderr 78 | stdin, _ := cmd.StdinPipe() 79 | for _, cronJob := range cron.CronJobs { 80 | stdin.Write([]byte(cronJob + "\n")) 81 | } 82 | 83 | for _, job := range cron.Jobs { 84 | if !job.Delete { 85 | stdin.Write([]byte(job.ToString() + "\n")) 86 | } 87 | } 88 | stdin.Close() 89 | return cmd.Run() 90 | } 91 | 92 | // Add a job to cron queue 93 | func (cron *Cron) Add(job QorJobInterface) (err error) { 94 | cron.parseJobs() 95 | defer cron.writeCronJob() 96 | 97 | var binaryFile string 98 | if binaryFile, err = filepath.Abs(os.Args[0]); err == nil { 99 | var jobs []*cronJob 100 | for _, cronJob := range cron.Jobs { 101 | if cronJob.JobID != job.GetJobID() { 102 | jobs = append(jobs, cronJob) 103 | } 104 | } 105 | 106 | if scheduler, ok := job.GetArgument().(Scheduler); ok && scheduler.GetScheduleTime() != nil { 107 | scheduleTime := scheduler.GetScheduleTime().In(time.Local) 108 | job.SetStatus(JobStatusScheduled) 109 | 110 | currentPath, _ := os.Getwd() 111 | jobs = append(jobs, &cronJob{ 112 | JobID: job.GetJobID(), 113 | Command: fmt.Sprintf("%d %d %d %d * cd %v; %v --qor-job %v\n", scheduleTime.Minute(), scheduleTime.Hour(), scheduleTime.Day(), scheduleTime.Month(), currentPath, binaryFile, job.GetJobID()), 114 | }) 115 | } else { 116 | cmd := exec.Command(binaryFile, "--qor-job", job.GetJobID()) 117 | if err = cmd.Start(); err == nil { 118 | jobs = append(jobs, &cronJob{JobID: job.GetJobID(), Pid: cmd.Process.Pid}) 119 | cmd.Process.Release() 120 | } 121 | } 122 | cron.Jobs = jobs 123 | } 124 | 125 | return 126 | } 127 | 128 | // Run a job from cron queue 129 | func (cron *Cron) Run(qorJob QorJobInterface) error { 130 | job := qorJob.GetJob() 131 | 132 | if job.Handler != nil { 133 | go func() { 134 | sigint := make(chan os.Signal, 1) 135 | 136 | // interrupt signal sent from terminal 137 | signal.Notify(sigint, syscall.SIGINT) 138 | // sigterm signal sent from kubernetes 139 | signal.Notify(sigint, syscall.SIGTERM) 140 | 141 | i := <-sigint 142 | 143 | qorJob.SetProgressText(fmt.Sprintf("Worker killed by signal %s", i.String())) 144 | qorJob.SetStatus(JobStatusKilled) 145 | 146 | qorJob.StopReferesh() 147 | os.Exit(int(reflect.ValueOf(i).Int())) 148 | }() 149 | 150 | qorJob.StartReferesh() 151 | defer qorJob.StopReferesh() 152 | 153 | err := job.Handler(qorJob.GetSerializableArgument(qorJob), qorJob) 154 | if err == nil { 155 | cron.parseJobs() 156 | defer cron.writeCronJob() 157 | for _, cronJob := range cron.Jobs { 158 | if cronJob.JobID == qorJob.GetJobID() { 159 | cronJob.Delete = true 160 | } 161 | } 162 | } 163 | return err 164 | } 165 | 166 | return errors.New("no handler found for job " + job.Name) 167 | } 168 | 169 | // Kill a job from cron queue 170 | func (cron *Cron) Kill(job QorJobInterface) (err error) { 171 | cron.parseJobs() 172 | defer cron.writeCronJob() 173 | 174 | for _, cronJob := range cron.Jobs { 175 | if cronJob.JobID == job.GetJobID() { 176 | if process, err := os.FindProcess(cronJob.Pid); err == nil { 177 | if err = process.Kill(); err == nil { 178 | cronJob.Delete = true 179 | return nil 180 | } 181 | } 182 | return err 183 | } 184 | } 185 | return errors.New("failed to find job") 186 | } 187 | 188 | // Remove a job from cron queue 189 | func (cron *Cron) Remove(job QorJobInterface) error { 190 | cron.parseJobs() 191 | defer cron.writeCronJob() 192 | 193 | for _, cronJob := range cron.Jobs { 194 | if cronJob.JobID == job.GetJobID() { 195 | if cronJob.Pid == 0 { 196 | cronJob.Delete = true 197 | return nil 198 | } 199 | return errors.New("failed to remove current job as it is running") 200 | } 201 | } 202 | return errors.New("failed to find job") 203 | } 204 | -------------------------------------------------------------------------------- /job.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "github.com/qor/admin" 5 | "github.com/qor/qor" 6 | "github.com/qor/roles" 7 | ) 8 | 9 | // Job is a struct that hold Qor Job definations 10 | type Job struct { 11 | Name string 12 | Group string 13 | Handler func(interface{}, QorJobInterface) error 14 | Permission *roles.Permission 15 | Queue Queue 16 | Resource *admin.Resource 17 | Worker *Worker 18 | } 19 | 20 | // NewStruct initialize job struct 21 | func (job *Job) NewStruct() interface{} { 22 | qorJobInterface := job.Worker.JobResource.NewStruct().(QorJobInterface) 23 | qorJobInterface.SetJob(job) 24 | return qorJobInterface 25 | } 26 | 27 | // GetQueue get defined job's queue 28 | func (job *Job) GetQueue() Queue { 29 | if job.Queue != nil { 30 | return job.Queue 31 | } 32 | return job.Worker.Queue 33 | } 34 | 35 | func (job Job) HasPermission(mode roles.PermissionMode, context *qor.Context) bool { 36 | if job.Permission == nil { 37 | return true 38 | } 39 | var roles = []interface{}{} 40 | for _, role := range context.Roles { 41 | roles = append(roles, role) 42 | } 43 | return job.Permission.HasPermission(mode, roles...) 44 | } 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qor", 3 | "description": "An enterprise-level open source content management system.", 4 | "version": "0.1.0", 5 | "main": "admin/views/assets/javascripts/app.js", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/qor/qor.git" 10 | }, 11 | "keywords": [ 12 | "qor", 13 | "cms", 14 | "go" 15 | ], 16 | "devDependencies": { 17 | "@babel/core": "^7.24.9", 18 | "@babel/preset-env": "^7.25.0", 19 | "gulp-babel": "^8.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /qor_job.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "database/sql/driver" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "log" 9 | "strings" 10 | "sync" 11 | "time" 12 | 13 | "github.com/jinzhu/gorm" 14 | "github.com/qor/admin" 15 | "github.com/qor/audited" 16 | "github.com/qor/serializable_meta" 17 | ) 18 | 19 | // QorJobInterface is a interface, defined methods that needs for a qor job 20 | type QorJobInterface interface { 21 | GetJobID() string 22 | GetJobName() string 23 | GetStatus() string 24 | SetStatus(string) error 25 | GetJob() *Job 26 | SetJob(*Job) 27 | 28 | GetProgress() uint 29 | SetProgress(uint) error 30 | GetProgressText() string 31 | SetProgressText(string) error 32 | GetLogs() []string 33 | AddLog(string) error 34 | GetResultsTable() ResultsTable 35 | AddResultsRow(...TableCell) error 36 | 37 | StartReferesh() 38 | StopReferesh() 39 | 40 | GetArgument() interface{} 41 | serializable_meta.SerializableMetaInterface 42 | } 43 | 44 | // ResultsTable is a struct, including importing/exporting results 45 | type ResultsTable struct { 46 | Name string `json:"-"` // only used for generate string column in database 47 | TableCells [][]TableCell 48 | } 49 | 50 | // Scan used to scan value from database into itself 51 | func (resultsTable *ResultsTable) Scan(data interface{}) error { 52 | switch values := data.(type) { 53 | case []byte: 54 | return json.Unmarshal(values, resultsTable) 55 | case string: 56 | return resultsTable.Scan([]byte(values)) 57 | default: 58 | return errors.New("unsupported data type for Qor Job error table") 59 | } 60 | } 61 | 62 | // Value used to read value from itself and save it into databae 63 | func (resultsTable ResultsTable) Value() (driver.Value, error) { 64 | result, err := json.Marshal(resultsTable) 65 | return string(result), err 66 | } 67 | 68 | // TableCell including Value, Error for a data cell 69 | type TableCell struct { 70 | Value string 71 | Error string 72 | } 73 | 74 | // QorJob predefined qor job struct, which will be used for Worker, if it doesn't include a job resource 75 | type QorJob struct { 76 | gorm.Model 77 | Status string `sql:"default:'new'"` 78 | Progress uint 79 | ProgressText string 80 | Log string `sql:"size:65532"` 81 | ResultsTable ResultsTable `sql:"size:65532"` 82 | 83 | mutex sync.Mutex `sql:"-"` 84 | 85 | stopReferesh bool `sql:"-"` 86 | inReferesh bool `sql:"-"` 87 | 88 | // Add `valid:"-"`` to make the QorJob work well with qor/validations 89 | // When the qor/validations auto exec the validate struct callback we get error 90 | // runtime: goroutine stack exceeds 1000000000-byte limit 91 | // fatal error: stack overflow 92 | Job *Job `sql:"-" valid:"-"` 93 | 94 | audited.AuditedModel 95 | serializable_meta.SerializableMeta 96 | } 97 | 98 | // GetJobID get job's ID from a qor job 99 | func (job *QorJob) GetJobID() string { 100 | return fmt.Sprint(job.ID) 101 | } 102 | 103 | // GetJobName get job's name from a qor job 104 | func (job *QorJob) GetJobName() string { 105 | return job.Kind 106 | } 107 | 108 | // GetStatus get job's status from a qor job 109 | func (job *QorJob) GetStatus() string { 110 | return job.Status 111 | } 112 | 113 | // SetStatus set job's status to a qor job instance 114 | func (job *QorJob) SetStatus(status string) error { 115 | job.mutex.Lock() 116 | defer job.mutex.Unlock() 117 | 118 | job.Status = status 119 | if status == JobStatusDone { 120 | job.Progress = 100 121 | } 122 | 123 | if job.shouldCallSave() { 124 | return job.callSave() 125 | } 126 | 127 | return nil 128 | } 129 | 130 | func (job *QorJob) shouldCallSave() bool { 131 | return !job.inReferesh || job.stopReferesh 132 | } 133 | 134 | func (job *QorJob) StartReferesh() { 135 | job.mutex.Lock() 136 | defer job.mutex.Unlock() 137 | if !job.inReferesh { 138 | job.inReferesh = true 139 | job.stopReferesh = false 140 | 141 | go func() { 142 | job.referesh() 143 | }() 144 | } 145 | } 146 | 147 | func (job *QorJob) StopReferesh() { 148 | job.mutex.Lock() 149 | defer job.mutex.Unlock() 150 | 151 | err := job.callSave() 152 | if err != nil { 153 | log.Println(err) 154 | } 155 | 156 | job.stopReferesh = true 157 | } 158 | 159 | func (job *QorJob) referesh() { 160 | job.mutex.Lock() 161 | defer job.mutex.Unlock() 162 | 163 | err := job.callSave() 164 | if err != nil { 165 | log.Println(err) 166 | } 167 | 168 | if job.stopReferesh { 169 | job.inReferesh = false 170 | job.stopReferesh = false 171 | } else { 172 | time.AfterFunc(5*time.Second, job.referesh) 173 | } 174 | } 175 | 176 | func (job *QorJob) callSave() error { 177 | worker := job.GetJob().Worker 178 | context := worker.Admin.NewContext(nil, nil).Context 179 | return worker.JobResource.CallSave(job, context) 180 | } 181 | 182 | // SetJob set `Job` for a qor job instance 183 | func (job *QorJob) SetJob(j *Job) { 184 | job.Kind = j.Name 185 | job.Job = j 186 | } 187 | 188 | // GetJob get predefined job for a qor job instance 189 | func (job *QorJob) GetJob() *Job { 190 | if job.Job != nil { 191 | return job.Job 192 | } 193 | return nil 194 | } 195 | 196 | // GetArgument get job's argument 197 | func (job *QorJob) GetArgument() interface{} { 198 | return job.GetSerializableArgument(job) 199 | } 200 | 201 | // GetSerializableArgumentResource get job's argument's resource 202 | func (job *QorJob) GetSerializableArgumentResource() *admin.Resource { 203 | if j := job.GetJob(); j != nil { 204 | return j.Resource 205 | } 206 | return nil 207 | } 208 | 209 | // GetProgress get qor job's progress 210 | func (job *QorJob) GetProgress() uint { 211 | return job.Progress 212 | } 213 | 214 | // SetProgress set qor job's progress 215 | func (job *QorJob) SetProgress(progress uint) error { 216 | job.mutex.Lock() 217 | defer job.mutex.Unlock() 218 | 219 | if progress > 100 { 220 | progress = 100 221 | } 222 | job.Progress = progress 223 | 224 | if job.shouldCallSave() { 225 | return job.callSave() 226 | } 227 | 228 | return nil 229 | } 230 | 231 | // GetProgressText get qor job's progress text 232 | func (job *QorJob) GetProgressText() string { 233 | return job.ProgressText 234 | } 235 | 236 | // SetProgressText set qor job's progress text 237 | func (job *QorJob) SetProgressText(str string) error { 238 | job.mutex.Lock() 239 | defer job.mutex.Unlock() 240 | 241 | job.ProgressText = str 242 | if job.shouldCallSave() { 243 | return job.callSave() 244 | } 245 | 246 | return nil 247 | } 248 | 249 | // GetLogs get qor job's logs 250 | func (job *QorJob) GetLogs() []string { 251 | return strings.Split(job.Log, "\n") 252 | } 253 | 254 | // AddLog add a log to qor job 255 | func (job *QorJob) AddLog(log string) error { 256 | job.mutex.Lock() 257 | defer job.mutex.Unlock() 258 | 259 | fmt.Println(log) 260 | job.Log += "\n" + log 261 | if job.shouldCallSave() { 262 | return job.callSave() 263 | } 264 | 265 | return nil 266 | } 267 | 268 | // GetResultsTable get the job's process logs 269 | func (job *QorJob) GetResultsTable() ResultsTable { 270 | return job.ResultsTable 271 | } 272 | 273 | // AddResultsRow add a row of process results to a job 274 | func (job *QorJob) AddResultsRow(cells ...TableCell) error { 275 | job.mutex.Lock() 276 | defer job.mutex.Unlock() 277 | 278 | job.ResultsTable.TableCells = append(job.ResultsTable.TableCells, cells) 279 | if job.shouldCallSave() { 280 | return job.callSave() 281 | } 282 | 283 | return nil 284 | } 285 | -------------------------------------------------------------------------------- /queue.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | // Queue is an interface defined methods need for a job queue 4 | type Queue interface { 5 | Add(QorJobInterface) error 6 | Run(QorJobInterface) error 7 | Kill(QorJobInterface) error 8 | Remove(QorJobInterface) error 9 | } 10 | -------------------------------------------------------------------------------- /queue/kubernetes/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Backend for QOR Worker 2 | 3 | This package provides [QOR worker](http://github.com/qor/worker)'s backend based on [Kubernetes Job](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/) 4 | 5 | ## Basic Usage 6 | 7 | In the basic usage mode, we will collect currently running pod's information like containers, volumes to create a new job pod to complete your requests. 8 | 9 | ```go 10 | kubernetesBackend, err := kubernetes.New(&kubernetes.Config{}) 11 | 12 | Worker := worker.New(&worker.Config{ 13 | Queue: kubernetesBackend, 14 | }) 15 | 16 | Worker.RegisterJob(&worker.Job{ 17 | Name: "Send Newsletter", 18 | Handler: func(argument interface{}, qorJob worker.QorJobInterface) error { 19 | }) 20 | ``` 21 | 22 | ## Advanced Usage 23 | 24 | For advanced requirements, like manage job's priority, cpu/memory's requests/limits, you could customize Job's template based on your requirements. 25 | 26 | For example: 27 | 28 | ```go 29 | func main() { 30 | kubernetesBackend, err := kubernetes.New(&kubernetes.Config{ 31 | JobTemplateMaker: func(qorJob worker.QorJobInterface) string { 32 | // Job `process order` has higher priority than other jobs 33 | if qorJob.GetJobName() == "process_order" { 34 | return ` 35 | apiVersion: batch/v1 36 | kind: Job 37 | metadata: 38 | name: jobname 39 | spec: 40 | template: 41 | spec: 42 | containers: 43 | - name: app 44 | image: my_image 45 | priorityClassName: high-priority 46 | ` 47 | } 48 | 49 | return ` 50 | apiVersion: batch/v1 51 | kind: Job 52 | metadata: 53 | name: jobname 54 | spec: 55 | template: 56 | spec: 57 | containers: 58 | - name: app 59 | image: my_image 60 | resources: 61 | limits: 62 | cpu: "750m" 63 | priorityClassName: low-priority 64 | ` 65 | }, 66 | }) 67 | 68 | Worker := worker.New(&worker.Config{ 69 | Queue: kubernetesBackend, 70 | }) 71 | } 72 | ``` 73 | -------------------------------------------------------------------------------- /queue/kubernetes/kubernetes.go: -------------------------------------------------------------------------------- 1 | package kubernetes 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "net" 8 | "os" 9 | "path/filepath" 10 | 11 | "github.com/ghodss/yaml" 12 | "github.com/qor/worker" 13 | "k8s.io/api/batch/v1" 14 | corev1 "k8s.io/api/core/v1" 15 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 | "k8s.io/client-go/kubernetes" 17 | "k8s.io/client-go/rest" 18 | ) 19 | 20 | var _ worker.Queue = &Kubernetes{} 21 | 22 | // Kubernetes implemented a worker Queue based on kubernetes jobs 23 | type Kubernetes struct { 24 | Clientset *kubernetes.Clientset 25 | Config *Config 26 | } 27 | 28 | // Config kubernetes config 29 | type Config struct { 30 | Namespace string 31 | JobTemplateMaker func(worker.QorJobInterface) string 32 | ClusterConfig *rest.Config 33 | } 34 | 35 | // New initialize Kubernetes 36 | func New(config *Config) (*Kubernetes, error) { 37 | var err error 38 | 39 | if config == nil { 40 | config = &Config{} 41 | } 42 | 43 | if config.ClusterConfig == nil { 44 | config.ClusterConfig, err = rest.InClusterConfig() 45 | } 46 | 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | clientset, err := kubernetes.NewForConfig(config.ClusterConfig) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | return &Kubernetes{Clientset: clientset, Config: config}, nil 57 | } 58 | 59 | // GetCurrentPod get current pod 60 | func (k8s *Kubernetes) GetCurrentPod() *corev1.Pod { 61 | var ( 62 | podlist, err = k8s.Clientset.Core().Pods("").List(metav1.ListOptions{}) 63 | localeIP = GetLocalIP() 64 | ) 65 | 66 | if err == nil { 67 | for _, item := range podlist.Items { 68 | if item.Status.PodIP == localeIP { 69 | return &item 70 | } 71 | } 72 | } 73 | return nil 74 | } 75 | 76 | // GetJobSpec get job spec 77 | func (k8s *Kubernetes) GetJobSpec(qorJob worker.QorJobInterface) (*v1.Job, error) { 78 | var ( 79 | k8sJob = &v1.Job{} 80 | currentPod = k8s.GetCurrentPod() 81 | namespace = currentPod.GetNamespace() 82 | ) 83 | 84 | if k8s.Config.Namespace != "" { 85 | namespace = k8s.Config.Namespace 86 | } 87 | 88 | if k8s.Config.JobTemplateMaker != nil { 89 | if err := yaml.Unmarshal([]byte(k8s.Config.JobTemplateMaker(qorJob)), k8sJob); err != nil { 90 | return nil, err 91 | } 92 | if k8sJob.ObjectMeta.Namespace != "" { 93 | namespace = k8sJob.ObjectMeta.Namespace 94 | } 95 | } else { 96 | if marshaledContainers, err := json.Marshal(currentPod.Spec.Containers); err == nil { 97 | json.Unmarshal(marshaledContainers, k8sJob.Spec.Template.Spec.Containers) 98 | } 99 | 100 | if marshaledVolumes, err := json.Marshal(currentPod.Spec.Volumes); err == nil { 101 | json.Unmarshal(marshaledVolumes, k8sJob.Spec.Template.Spec.Volumes) 102 | } 103 | } 104 | 105 | if k8sJob.TypeMeta.Kind == "" { 106 | k8sJob.TypeMeta.Kind = "Job" 107 | } 108 | 109 | if k8sJob.TypeMeta.APIVersion == "" { 110 | k8sJob.TypeMeta.APIVersion = "batch/v1" 111 | } 112 | 113 | if k8sJob.ObjectMeta.Namespace == "" { 114 | k8sJob.ObjectMeta.Namespace = namespace 115 | } 116 | 117 | return k8sJob, nil 118 | } 119 | 120 | // Add a job to k8s queue 121 | func (k8s *Kubernetes) Add(qorJob worker.QorJobInterface) error { 122 | var ( 123 | jobName = fmt.Sprintf("qor-job-%v", qorJob.GetJobID()) 124 | k8sJob, err = k8s.GetJobSpec(qorJob) 125 | currentPath, _ = os.Getwd() 126 | binaryFile, _ = filepath.Abs(os.Args[0]) 127 | ) 128 | 129 | if err == nil { 130 | k8sJob.ObjectMeta.Name = jobName 131 | k8sJob.Spec.Template.ObjectMeta.Name = jobName 132 | 133 | if k8sJob.Spec.Template.Spec.RestartPolicy == "" { 134 | k8sJob.Spec.Template.Spec.RestartPolicy = "Never" 135 | } 136 | 137 | for idx, container := range k8sJob.Spec.Template.Spec.Containers { 138 | if len(container.Command) == 0 || k8s.Config.JobTemplateMaker == nil { 139 | container.Command = []string{binaryFile, "--qor-job", qorJob.GetJobID()} 140 | } 141 | if container.WorkingDir == "" || k8s.Config.JobTemplateMaker == nil { 142 | container.WorkingDir = currentPath 143 | } 144 | 145 | k8sJob.Spec.Template.Spec.Containers[idx] = container 146 | } 147 | 148 | _, err = k8s.Clientset.Batch().Jobs(k8sJob.ObjectMeta.GetNamespace()).Create(k8sJob) 149 | } 150 | return err 151 | } 152 | 153 | // Run a job from k8s queue 154 | func (k8s *Kubernetes) Run(qorJob worker.QorJobInterface) error { 155 | job := qorJob.GetJob() 156 | 157 | if job.Handler != nil { 158 | return job.Handler(qorJob.GetSerializableArgument(qorJob), qorJob) 159 | } 160 | 161 | return errors.New("no handler found for job " + job.Name) 162 | } 163 | 164 | // Kill a job from k8s queue 165 | func (k8s *Kubernetes) Kill(qorJob worker.QorJobInterface) error { 166 | var ( 167 | k8sJob, err = k8s.GetJobSpec(qorJob) 168 | jobName = fmt.Sprintf("qor-job-%v", qorJob.GetJobID()) 169 | ) 170 | 171 | if err == nil { 172 | return k8s.Clientset.Batch().Jobs(k8sJob.ObjectMeta.GetNamespace()).Delete(jobName, &metav1.DeleteOptions{}) 173 | } 174 | return err 175 | } 176 | 177 | // Remove a job from k8s queue 178 | func (k8s *Kubernetes) Remove(qorJob worker.QorJobInterface) error { 179 | var ( 180 | k8sJob, err = k8s.GetJobSpec(qorJob) 181 | jobName = fmt.Sprintf("qor-job-%v", qorJob.GetJobID()) 182 | ) 183 | 184 | if err == nil { 185 | // TODO Don't remove if it is already running 186 | return k8s.Clientset.Batch().Jobs(k8sJob.ObjectMeta.GetNamespace()).Delete(jobName, &metav1.DeleteOptions{}) 187 | } 188 | return err 189 | } 190 | 191 | // GetLocalIP returns the non loopback local IP of the host 192 | func GetLocalIP() string { 193 | addrs, err := net.InterfaceAddrs() 194 | if err != nil { 195 | return "" 196 | } 197 | for _, address := range addrs { 198 | // check the address type and if it is not a loopback the display it 199 | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 200 | if ipnet.IP.To4() != nil { 201 | return ipnet.IP.String() 202 | } 203 | } 204 | } 205 | return "" 206 | } 207 | -------------------------------------------------------------------------------- /scheduler.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import "time" 4 | 5 | // Scheduler is a interface, for job used to `GetScheduleTime` 6 | type Scheduler interface { 7 | GetScheduleTime() *time.Time 8 | } 9 | 10 | // Schedule could be embedded as job argument, then the job will get run as scheduled feature 11 | type Schedule struct { 12 | ScheduleTime *time.Time 13 | } 14 | 15 | // GetScheduleTime get scheduled time 16 | func (schedule Schedule) GetScheduleTime() *time.Time { 17 | if scheduleTime := schedule.ScheduleTime; scheduleTime != nil { 18 | if scheduleTime.After(time.Now().Add(time.Minute)) { 19 | return scheduleTime 20 | } 21 | } 22 | return nil 23 | } 24 | -------------------------------------------------------------------------------- /views/themes/worker/actions/index/5.scope.tmpl: -------------------------------------------------------------------------------- 1 |
2 | 20 |
21 | -------------------------------------------------------------------------------- /views/themes/worker/assets/javascripts/worker.js: -------------------------------------------------------------------------------- 1 | "use strict";var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(r){return typeof r}:function(r){return r&&"function"==typeof Symbol&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r};!function(r){"function"==typeof define&&define.amd?define(["jquery"],r):"object"===("undefined"==typeof exports?"undefined":_typeof(exports))?r(require("jquery")):r(jQuery)}(function(h){var n="qor.worker",r="enable."+n,e="click."+n,s=".qor-worker-form",i=".qor-worker-form-list",m=".qor-worker--progress",d=".qor-button--back",p=".qor-js-table",g=".is-selected";function w(r){document.querySelector("#qor-worker--progress")&&document.querySelector("#qor-worker--progress").MaterialProgress.setProgress(r)}function v(r,e){this.$element=h(r),this.options=h.extend({},v.DEFAULTS,h.isPlainObject(e)&&e),this.init()}return v.prototype={constructor:v,init:function(){this.bind(),this.formOpened=!1,h(".qor-worker-form--show").length&&(this.formOpened=!0),w(h("#qor-worker--progress").data("progress")),h(".qor-slideout").is(":visible")||h.fn.qorSliderAfterShow.updateWorkerProgress()},bind:function(){this.$element.on(e,".qor-worker--new",this.showForm.bind(this)).on(e,d,this.hideForm.bind(this))},unbind:function(){this.$element.off(e)},hideForm:function(r){r.preventDefault(),this.$element.find(s).find(">li").show().removeClass("current").find("form").addClass("hidden"),h(d).addClass("hidden"),h(i).show(),this.formOpened=!1,window.onbeforeunload=null,h.fn.qorSlideoutBeforeHide=null},showForm:function(r){var e=h(r.target);if(r.preventDefault(),!this.formOpened){var o=e.closest("li"),t=e.closest(s),n=e.closest(i);t.find(">li").hide().removeClass("current"),o.addClass("current").show(),h(d).removeClass("hidden"),o.find(i).hide(),n.show().find("form").removeClass("hidden"),this.formOpened=!0}},destroy:function(){this.unbind(),v.getWorkerProgressIntervId&&window.clearInterval(v.getWorkerProgressIntervId)}},v.DEFAULTS={},v.POPOVERTEMPLATE='',v.plugin=function(t){return this.each(function(){var r,e=h(this),o=e.data(n);if(!o){if(/destroy/.test(t))return;e.data(n,o=new v(this,t))}"string"==typeof t&&h.isFunction(r=o[t])&&r.apply(o)})},h.fn.qorSliderAfterShow.updateWorkerProgress=function(r){h(".workers-log-output").length&&(v.getWorkerProgressIntervId=window.setInterval(v.updateWorkerProgress,2e3,r))},v.updateTableStatus=function(r){var e=h(p).find(g),o=h(m).data().statusName;e.find('td[data-heading="'+o+'"]').find(".qor-table__content").html(r)},v.isScrollToBottom=function(r){return r.clientHeight+r.scrollTop<=r.scrollHeight},v.updateWorkerProgress=function(r){var e=r,l=h(".workers-log-output"),a=h(".qor-worker--progress-value"),u=h(".qor-worker--progress-status"),o=h(m),t=h(p).find(g),f=["killed","exception","cancelled","scheduled"];if(l.length){if(o.length)var n=o.data();if(t.length&&n&&n.statusName)var c=t.find('td[data-heading="'+n.statusName+'"]').find(".qor-table__content").html();if(o.length&&o.length&&-1==f.indexOf(n.status))return 100<=n.progress?(window.clearInterval(v.getWorkerProgressIntervId),v.updateTableStatus(n.status),h(".qor-workers-abort").addClass("hidden"),void h(".qor-workers-rerun").removeClass("hidden")):void h.ajax({url:e,method:"GET",dataType:"html",processData:!1,contentType:!1}).done(function(r){var e=h(r),o=e.find(m).data(),t=o.progress,n=o.status,s=-1!=f.indexOf(n);a.html(t),u.html(n),s&&u.addClass("highlight"),w(t);var i=h.trim(e.find(".workers-log-output").html()),d=e.find(".workers-error-output");v.isScrollToBottom(l[0])?l.html(i).scrollTop(l[0].scrollHeight):l.html(i),d.length&&h(".workers-error-output").html(d.html()),c!=n&&v.updateTableStatus(n),(100<=t||s)&&(window.clearInterval(v.getWorkerProgressIntervId),h(".qor-workers-abort").addClass("hidden"),h(".qor-workers-rerun").removeClass("hidden"),h(".qor-worker--progress-result").html(e.find(".qor-worker--progress-result").html()))});window.clearInterval(v.getWorkerProgressIntervId)}},h(function(){var e='[data-toggle="qor.workers"]';h(document).on("disable.qor.worker",function(r){v.plugin.call(h(e,r.target),"destroy")}).on(r,function(r){v.plugin.call(h(e,r.target))}).triggerHandler(r)}),v}); -------------------------------------------------------------------------------- /views/themes/worker/assets/javascripts/worker/workers.js: -------------------------------------------------------------------------------- 1 | (function(factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | // AMD. Register as anonymous module. 4 | define(['jquery'], factory); 5 | } else if (typeof exports === 'object') { 6 | // Node / CommonJS 7 | factory(require('jquery')); 8 | } else { 9 | // Browser globals. 10 | factory(jQuery); 11 | } 12 | })(function($) { 13 | 'use strict'; 14 | 15 | let NAMESPACE = 'qor.worker', 16 | EVENT_ENABLE = 'enable.' + NAMESPACE, 17 | EVENT_DISABLE = 'disable.' + NAMESPACE, 18 | EVENT_CLICK = 'click.' + NAMESPACE, 19 | CLASS_NEW_WORKER = '.qor-worker--new', 20 | CLASS_WORKER_CONTAINER = '.qor-worker-form', 21 | CLASS_WORKER_LIST = '.qor-worker-form-list', 22 | CLASS_WORKER_PROGRESS = '.qor-worker--progress', 23 | CLASS_WORKER_SHOW = '.qor-worker-form--show', 24 | CLASS_BUTTON_BACK = '.qor-button--back', 25 | CLASS_TABLE = '.qor-js-table', 26 | CLASS_SELECT = '.is-selected'; 27 | 28 | function updateProgress(progress) { 29 | let $progress = document.querySelector('#qor-worker--progress'); 30 | if ($progress) { 31 | document.querySelector('#qor-worker--progress').MaterialProgress.setProgress(progress); 32 | } 33 | } 34 | 35 | function QorWorker(element, options) { 36 | this.$element = $(element); 37 | this.options = $.extend({}, QorWorker.DEFAULTS, $.isPlainObject(options) && options); 38 | this.init(); 39 | } 40 | 41 | QorWorker.prototype = { 42 | constructor: QorWorker, 43 | 44 | init: function() { 45 | this.bind(); 46 | this.formOpened = false; 47 | if ($(CLASS_WORKER_SHOW).length) { 48 | this.formOpened = true; 49 | } 50 | 51 | updateProgress($('#qor-worker--progress').data('progress')); 52 | 53 | if (!$('.qor-slideout').is(':visible')) { 54 | $.fn.qorSliderAfterShow.updateWorkerProgress(); 55 | } 56 | }, 57 | 58 | bind: function() { 59 | this.$element.on(EVENT_CLICK, CLASS_NEW_WORKER, this.showForm.bind(this)).on(EVENT_CLICK, CLASS_BUTTON_BACK, this.hideForm.bind(this)); 60 | }, 61 | 62 | unbind: function() { 63 | this.$element.off(EVENT_CLICK); 64 | }, 65 | 66 | hideForm: function(e) { 67 | e.preventDefault(); 68 | 69 | var $parent = this.$element; 70 | var $lists = $parent.find(CLASS_WORKER_CONTAINER).find('>li'); 71 | 72 | $lists 73 | .show() 74 | .removeClass('current') 75 | .find('form') 76 | .addClass('hidden'); 77 | $(CLASS_BUTTON_BACK).addClass('hidden'); 78 | $(CLASS_WORKER_LIST).show(); 79 | 80 | this.formOpened = false; 81 | 82 | window.onbeforeunload = null; 83 | $.fn.qorSlideoutBeforeHide = null; 84 | }, 85 | 86 | showForm: function(e) { 87 | var $target = $(e.target); 88 | e.preventDefault(); 89 | 90 | if (this.formOpened) { 91 | return; 92 | } 93 | 94 | var $targetList = $target.closest('li'); 95 | var $parent = $target.closest(CLASS_WORKER_CONTAINER); 96 | var $parentList = $target.closest(CLASS_WORKER_LIST); 97 | var $lists = $parent.find('>li'); 98 | 99 | $lists.hide().removeClass('current'); 100 | 101 | $targetList.addClass('current').show(); 102 | $(CLASS_BUTTON_BACK).removeClass('hidden'); 103 | $targetList.find(CLASS_WORKER_LIST).hide(); 104 | 105 | $parentList 106 | .show() 107 | .find('form') 108 | .removeClass('hidden'); 109 | this.formOpened = true; 110 | }, 111 | 112 | destroy: function() { 113 | this.unbind(); 114 | QorWorker.getWorkerProgressIntervId && window.clearInterval(QorWorker.getWorkerProgressIntervId); 115 | } 116 | }; 117 | 118 | QorWorker.DEFAULTS = {}; 119 | QorWorker.POPOVERTEMPLATE = ``; 130 | 131 | QorWorker.plugin = function(options) { 132 | return this.each(function() { 133 | var $this = $(this); 134 | var data = $this.data(NAMESPACE); 135 | var fn; 136 | 137 | if (!data) { 138 | if (/destroy/.test(options)) { 139 | return; 140 | } 141 | 142 | $this.data(NAMESPACE, (data = new QorWorker(this, options))); 143 | } 144 | 145 | if (typeof options === 'string' && $.isFunction((fn = data[options]))) { 146 | fn.apply(data); 147 | } 148 | }); 149 | }; 150 | 151 | $.fn.qorSliderAfterShow.updateWorkerProgress = function(url) { 152 | if (!$('.workers-log-output').length) { 153 | return; 154 | } 155 | QorWorker.getWorkerProgressIntervId = window.setInterval(QorWorker.updateWorkerProgress, 2000, url); 156 | }; 157 | 158 | QorWorker.updateTableStatus = function(status) { 159 | var $selectedItem = $(CLASS_TABLE).find(CLASS_SELECT); 160 | var statusName = $(CLASS_WORKER_PROGRESS).data().statusName; 161 | 162 | $selectedItem 163 | .find('td[data-heading="' + statusName + '"]') 164 | .find('.qor-table__content') 165 | .html(status); 166 | }; 167 | 168 | QorWorker.isScrollToBottom = function(element) { 169 | return element.clientHeight + element.scrollTop <= element.scrollHeight; 170 | }; 171 | 172 | QorWorker.updateWorkerProgress = function(url) { 173 | let progressURL = url, 174 | $logContainer = $('.workers-log-output'), 175 | $progressValue = $('.qor-worker--progress-value'), 176 | $progressStatusStatus = $('.qor-worker--progress-status'), 177 | $progress = $(CLASS_WORKER_PROGRESS), 178 | $selectTR = $(CLASS_TABLE).find(CLASS_SELECT), 179 | status = ['killed', 'exception', 'cancelled', 'scheduled']; 180 | 181 | if (!$logContainer.length) { 182 | return; 183 | } 184 | if ($progress.length) { 185 | var progressData = $progress.data(); 186 | } 187 | 188 | if ($selectTR.length && progressData && progressData.statusName) { 189 | var orignialStatus = $selectTR 190 | .find('td[data-heading="' + progressData.statusName + '"]') 191 | .find('.qor-table__content') 192 | .html(); 193 | } 194 | 195 | if (!$progress.length || !$progress.length || status.indexOf(progressData.status) != -1) { 196 | window.clearInterval(QorWorker.getWorkerProgressIntervId); 197 | return; 198 | } 199 | 200 | if (progressData.progress >= 100) { 201 | window.clearInterval(QorWorker.getWorkerProgressIntervId); 202 | QorWorker.updateTableStatus(progressData.status); 203 | $('.qor-workers-abort').addClass('hidden'); 204 | $('.qor-workers-rerun').removeClass('hidden'); 205 | return; 206 | } 207 | 208 | $.ajax({ 209 | url: progressURL, 210 | method: 'GET', 211 | dataType: 'html', 212 | processData: false, 213 | contentType: false 214 | }).done(function(html) { 215 | let $html = $(html), 216 | contentData = $html.find(CLASS_WORKER_PROGRESS).data(), 217 | currentStatus = contentData.progress, 218 | progressStatusStatus = contentData.status, 219 | isNotNormalStatus = status.indexOf(progressStatusStatus) != -1; 220 | 221 | $progressValue.html(currentStatus); 222 | $progressStatusStatus.html(progressStatusStatus); 223 | 224 | if (isNotNormalStatus) { 225 | $progressStatusStatus.addClass('highlight'); 226 | } 227 | 228 | // set status progress 229 | updateProgress(currentStatus); 230 | 231 | // update process log 232 | let log = $.trim($html.find('.workers-log-output').html()), 233 | $errorTable = $html.find('.workers-error-output'); 234 | 235 | if (QorWorker.isScrollToBottom($logContainer[0])) { 236 | $logContainer.html(log).scrollTop($logContainer[0].scrollHeight); 237 | } else { 238 | $logContainer.html(log); 239 | } 240 | 241 | if ($errorTable.length) { 242 | $('.workers-error-output').html($errorTable.html()); 243 | } 244 | 245 | if (orignialStatus != progressStatusStatus) { 246 | QorWorker.updateTableStatus(progressStatusStatus); 247 | } 248 | 249 | if (currentStatus >= 100 || isNotNormalStatus) { 250 | window.clearInterval(QorWorker.getWorkerProgressIntervId); 251 | $('.qor-workers-abort').addClass('hidden'); 252 | $('.qor-workers-rerun').removeClass('hidden'); 253 | $('.qor-worker--progress-result').html($html.find('.qor-worker--progress-result').html()); 254 | } 255 | }); 256 | }; 257 | 258 | $(function() { 259 | var selector = '[data-toggle="qor.workers"]'; 260 | 261 | $(document) 262 | .on(EVENT_DISABLE, function(e) { 263 | QorWorker.plugin.call($(selector, e.target), 'destroy'); 264 | }) 265 | .on(EVENT_ENABLE, function(e) { 266 | QorWorker.plugin.call($(selector, e.target)); 267 | }) 268 | .triggerHandler(EVENT_ENABLE); 269 | }); 270 | 271 | return QorWorker; 272 | }); 273 | -------------------------------------------------------------------------------- /views/themes/worker/assets/stylesheets/worker.css: -------------------------------------------------------------------------------- 1 | .qor-workers--details .qor-form__actions .mdl-button{margin-left:16px}.qor-workers--details .workers-label{font-size:16px;margin:0 0 16px}.qor-workers--details .workers-label-title{font-size:12px;color:rgba(0,0,0,.54);font-weight:500;margin:0}.qor-workers--details [data-toggle='qor.workers']>div{margin:16px 0 8px}[data-toggle='qor.workers'] .qor-button--back{font-size:14px;color:#03a9f4;display:inline-block;margin-bottom:24px}[data-toggle='qor.workers'] .qor-button--back span{display:inline-block;vertical-align:middle}[data-toggle='qor.workers'] .qor-button--back .material-icons{font-size:14px;color:#03a9f4;vertical-align:middle;margin-right:8px}[data-toggle='qor.workers'] .qor-workers-buttons{float:right}[data-toggle='qor.workers'] .qor-worker-form{padding:0;margin:0}[data-toggle='qor.workers'] .qor-worker-form textarea{min-height:40px}[data-toggle='qor.workers'] .qor-worker-form li{list-style:none}[data-toggle='qor.workers'] .qor-worker-form li.current .qor-worker--new,[data-toggle='qor.workers'] .qor-worker-form li.qor-worker-form--show .qor-worker--new{padding-left:0;color:#000;cursor:default;font-size:16px;margin-bottom:16px}[data-toggle='qor.workers'] .qor-worker-form li.current>h5,[data-toggle='qor.workers'] .qor-worker-form li.qor-worker-form--show>h5{display:none}[data-toggle='qor.workers'] .qor-worker-form li>h5{font-size:16px;line-height:1;margin:24px 0 10px 0}[data-toggle='qor.workers'] .qor-worker-form-list .qor-worker--new{padding-left:16px}[data-toggle='qor.workers'] .qor-worker-form-list .qor-field{padding:0;margin-bottom:20px}[data-toggle='qor.workers'] .qor-worker-form-list .qor-field .mdl-textfield{margin-bottom:-20px}[data-toggle='qor.workers'] .qor-worker-form-list .qor-section-columns-2 .qor-field{padding-right:40px}[data-toggle='qor.workers'] .qor-worker-form-list .qor-field__block{padding-bottom:0}[data-toggle='qor.workers'] .qor-worker-form-list .qor-form__actions{margin-top:0}[data-toggle='qor.workers'] .qor-worker-form-list .qor-worker--new{margin:2px 0;display:inline-block;text-decoration:none}[data-toggle='qor.workers'] .workers-log-output{background-color:#222;color:#fff;font-family:menlo,Roboto,Helvetica,Arial,sans-serif;height:300px;padding:8px;overflow:auto;box-sizing:border-box}[data-toggle='qor.workers'] .workers-log-output p{line-height:1;font-size:12px;margin:0;margin-bottom:4px}[data-toggle='qor.workers'] .workers-error-output{max-height:500px;overflow:auto}[data-toggle='qor.workers'] .workers-error-output table{width:100%;margin:0}[data-toggle='qor.workers'] .qor-workers-buttons button{display:block;float:right}[data-toggle='qor.workers'] .qor-worker--progress .workers-label-content{float:left;width:105px}[data-toggle='qor.workers'] .qor-worker--progress .workers-label-content .highlight{font-weight:600;color:#ff4081}[data-toggle='qor.workers'] .qor-worker--progress .mdl-progress{float:left;margin-top:10px;width:calc(100% - 105px)}[data-toggle='qor.workers'] .qor-worker--progress .mdl-progress.has-errors-texts{width:calc(100% - 262px)}[data-toggle='qor.workers'] .qor-worker--progress .mdl-progress.has-errors-texts+a{display:inline-block;margin:3px 0 0 20px;text-transform:uppercase}[data-toggle='qor.workers'] .workers-error-output{margin:0}[data-toggle='qor.workers'] .worker-process-error{background-color:#ff4081;color:#fff}[data-toggle='qor.workers'] .qor-modal--worker-errors .mdl-card{max-width:80%} -------------------------------------------------------------------------------- /views/themes/worker/assets/stylesheets/worker/app.scss: -------------------------------------------------------------------------------- 1 | .qor-workers--details { 2 | .qor-form__actions { 3 | .mdl-button { 4 | margin-left: 16px; 5 | } 6 | } 7 | .workers-label { 8 | font-size: 16px; 9 | margin: 0 0 16px; 10 | } 11 | .workers-label-title { 12 | font-size: 12px; 13 | color: rgba(0, 0, 0, 0.54); 14 | font-weight: 500; 15 | margin: 0; 16 | } 17 | [data-toggle='qor.workers'] { 18 | > div { 19 | margin: 16px 0 8px; 20 | } 21 | } 22 | } 23 | 24 | [data-toggle='qor.workers'] { 25 | .qor-button--back { 26 | font-size: 14px; 27 | color: #03a9f4; 28 | display: inline-block; 29 | margin-bottom: 24px; 30 | span { 31 | display: inline-block; 32 | vertical-align: middle; 33 | } 34 | .material-icons { 35 | font-size: 14px; 36 | color: #03a9f4; 37 | vertical-align: middle; 38 | margin-right: 8px; 39 | } 40 | } 41 | .qor-workers-buttons { 42 | float: right; 43 | } 44 | .qor-worker-form { 45 | padding: 0; 46 | margin: 0; 47 | textarea { 48 | min-height: 40px; 49 | } 50 | li { 51 | list-style: none; 52 | &.current, 53 | &.qor-worker-form--show { 54 | .qor-worker--new { 55 | padding-left: 0; 56 | color: rgba(0, 0, 0, 75); 57 | cursor: default; 58 | font-size: 16px; 59 | margin-bottom: 16px; 60 | } 61 | > h5 { 62 | display: none; 63 | } 64 | } 65 | > h5 { 66 | font-size: 16px; 67 | line-height: 1; 68 | margin: 24px 0 10px 0; 69 | } 70 | } 71 | } 72 | .qor-worker-form-list { 73 | .qor-worker--new { 74 | padding-left: 16px; 75 | } 76 | .qor-field { 77 | padding: 0; 78 | margin-bottom: 20px; 79 | .mdl-textfield { 80 | margin-bottom: -20px; 81 | } 82 | } 83 | .qor-section-columns-2 .qor-field { 84 | padding-right: 40px; 85 | } 86 | .qor-field__block { 87 | padding-bottom: 0; 88 | } 89 | .qor-form__actions { 90 | margin-top: 0; 91 | } 92 | .qor-worker--new { 93 | margin: 2px 0; 94 | display: inline-block; 95 | text-decoration: none; 96 | } 97 | } 98 | .workers-log-output { 99 | background-color: #222; 100 | color: #fff; 101 | font-family: 'menlo', 'Roboto', 'Helvetica', 'Arial', sans-serif; 102 | height: 300px; 103 | padding: 8px; 104 | overflow: auto; 105 | box-sizing: border-box; 106 | p { 107 | line-height: 1; 108 | font-size: 12px; 109 | margin: 0; 110 | margin-bottom: 4px; 111 | } 112 | } 113 | .workers-error-output { 114 | max-height: 500px; 115 | overflow: auto; 116 | table { 117 | width: 100%; 118 | margin: 0; 119 | } 120 | } 121 | .qor-workers-buttons { 122 | button { 123 | display: block; 124 | float: right; 125 | } 126 | } 127 | .qor-worker--progress { 128 | .workers-label-content { 129 | float: left; 130 | width: 105px; 131 | .highlight { 132 | font-weight: 600; 133 | color: #ff4081; 134 | } 135 | } 136 | .mdl-progress { 137 | float: left; 138 | margin-top: 10px; 139 | width: calc(100% - 105px); 140 | &.has-errors-texts { 141 | width: calc(100% - 262px); 142 | & + a { 143 | display: inline-block; 144 | margin: 3px 0 0 20px; 145 | text-transform: uppercase; 146 | } 147 | } 148 | } 149 | } 150 | .workers-error-output { 151 | margin: 0; 152 | } 153 | .worker-process-error { 154 | background-color: rgb(255, 64, 129); 155 | color: #fff; 156 | } 157 | .qor-modal--worker-errors { 158 | .mdl-card { 159 | max-width: 80%; 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /views/themes/worker/edit.tmpl: -------------------------------------------------------------------------------- 1 | {{$job := .Result}} 2 | {{$actions := load_actions "show"}} 3 | 4 | {{if $actions}} 5 |
6 | {{$actions}} 7 |
8 | {{end}} 9 | 10 |
11 | {{render "shared/flashes"}} 12 | {{render "shared/errors"}} 13 | 14 | {{if $job}} 15 |
16 | {{if eq $job.GetStatus "scheduled"}} 17 |
{{$job.GetJobName}}
18 | 19 |
20 |
21 | 22 | 23 | {{render_form $job (new_sections $job.GetJob.Worker.JobResource)}} 24 | 25 |
26 | 29 | 30 | 33 |
34 |
35 |
36 | {{else}} 37 |
38 |
{{$job.GetJobName}}
39 | 40 |
41 |

{{t "qor_worker.jobs.Status" "Status"}}

42 |

43 | {{$job.GetStatus}} ({{$job.GetProgress}}%) 44 |

45 | 46 |
47 |
48 | 49 |
50 |

{{t "qor_worker.jobs.job_log" "Job Log"}}

51 |
52 | {{if gt (len $job.GetLogs) 1 -}} 53 | {{range $log := $job.GetLogs -}} 54 |

{{$log}}

55 | {{- end}} 56 | {{- end}} 57 |
58 |
59 | 60 |
61 | {{if $job.GetProgressText}} 62 |

{{raw $job.GetProgressText}}

63 | {{end}} 64 |
65 | 66 | {{if $job.GetResultsTable.TableCells}} 67 |
68 |

{{t "qor_worker.jobs.job_reports" "Job Reports"}}

69 |
70 | 71 | {{range $cells := $job.GetResultsTable.TableCells}} 72 | 73 | {{range $cell := $cells}} 74 | 80 | {{end}} 81 | 82 | {{end}} 83 |
75 | {{$cell.Value}} 76 | {{if $cell.Error}} 77 |

{{$cell.Error}}

78 | {{end}} 79 |
84 |
85 |
86 | {{end}} 87 | 88 | {{if has_update_permission .Resource}} 89 |
90 |
91 | 94 |
95 | 96 |
97 | 100 |
101 |
102 | {{end}} 103 |
104 | {{end}} 105 |
106 | {{end}} 107 |
108 | -------------------------------------------------------------------------------- /views/themes/worker/new.tmpl: -------------------------------------------------------------------------------- 1 | {{$resource := .Resource}} 2 | {{$worker := .Result}} 3 | {{$grouped_jobs := (get_grouped_jobs $worker .)}} 4 | 5 |
6 | {{render "shared/flashes"}} 7 | {{render "shared/errors"}} 8 | 9 |
10 |
11 | 14 |
    15 | {{range $title, $jobs := $grouped_jobs}} 16 | {{$show_form := (and (eq (len $grouped_jobs) 1) (eq (len $jobs) 1))}} 17 |
  • 18 | {{if $title}} 19 |
    {{t (print "qor_worker.job_groups." $title) $title}}
    20 | {{else}} 21 |
    {{t "qor_worker.new_worker.worker_jobs" "Worker Jobs"}}
    22 | {{end}} 23 | 24 | {{range $job := $jobs}} 25 |
    26 | {{t (print "qor_worker.jobs." $job.Name) $job.Name}} 27 |
    28 | 29 | {{render_form $job.NewStruct (new_sections $worker.JobResource)}} 30 | 31 |
    32 | 33 | {{if not $show_form}}{{t "qor_admin.form.cancel" "Cancel"}}{{end}} 34 |
    35 |
    36 |
    37 | {{end}} 38 |
  • 39 | {{end}} 40 |
41 |
42 |
43 |
44 | -------------------------------------------------------------------------------- /worker.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "runtime/debug" 9 | 10 | "github.com/jinzhu/gorm" 11 | "github.com/qor/admin" 12 | "github.com/qor/qor" 13 | "github.com/qor/qor/resource" 14 | "github.com/qor/roles" 15 | ) 16 | 17 | const ( 18 | // JobStatusScheduled job status scheduled 19 | JobStatusScheduled = "scheduled" 20 | // JobStatusCancelled job status cancelled 21 | JobStatusCancelled = "cancelled" 22 | // JobStatusNew job status new 23 | JobStatusNew = "new" 24 | // JobStatusRunning job status running 25 | JobStatusRunning = "running" 26 | // JobStatusDone job status done 27 | JobStatusDone = "done" 28 | // JobStatusException job status exception 29 | JobStatusException = "exception" 30 | // JobStatusKilled job status killed 31 | JobStatusKilled = "killed" 32 | ) 33 | 34 | // New create Worker with Config 35 | func New(config ...*Config) *Worker { 36 | var cfg = &Config{} 37 | if len(config) > 0 { 38 | cfg = config[0] 39 | } 40 | 41 | if cfg.Job == nil { 42 | cfg.Job = &QorJob{} 43 | } 44 | 45 | if cfg.Queue == nil { 46 | cfg.Queue = NewCronQueue() 47 | } 48 | 49 | return &Worker{Config: cfg} 50 | } 51 | 52 | // Config worker config 53 | type Config struct { 54 | Queue Queue 55 | Job QorJobInterface 56 | Admin *admin.Admin 57 | } 58 | 59 | // Worker worker definition 60 | type Worker struct { 61 | *Config 62 | JobResource *admin.Resource 63 | Jobs []*Job 64 | mounted bool 65 | } 66 | 67 | // ConfigureQorResourceBeforeInitialize a method used to config Worker for qor admin 68 | func (worker *Worker) ConfigureQorResourceBeforeInitialize(res resource.Resourcer) { 69 | if res, ok := res.(*admin.Resource); ok { 70 | res.GetAdmin().RegisterViewPath("github.com/qor/worker/views") 71 | res.UseTheme("worker") 72 | 73 | worker.Admin = res.GetAdmin() 74 | worker.JobResource = worker.Admin.NewResource(worker.Config.Job) 75 | worker.JobResource.UseTheme("worker") 76 | worker.JobResource.Meta(&admin.Meta{Name: "Name", Valuer: func(record interface{}, context *qor.Context) interface{} { 77 | return record.(QorJobInterface).GetJobName() 78 | }}) 79 | worker.JobResource.IndexAttrs("ID", "Name", "Status", "CreatedAt") 80 | worker.JobResource.Name = res.Name 81 | worker.JobResource.Permission = res.Permission 82 | 83 | for _, status := range []string{JobStatusScheduled, JobStatusNew, JobStatusRunning, JobStatusDone, JobStatusException} { 84 | var status = status 85 | worker.JobResource.Scope(&admin.Scope{Name: status, Handler: func(db *gorm.DB, ctx *qor.Context) *gorm.DB { 86 | return db.Where("status = ?", status) 87 | }}) 88 | } 89 | 90 | // default scope 91 | worker.JobResource.Scope(&admin.Scope{ 92 | Handler: func(db *gorm.DB, ctx *qor.Context) *gorm.DB { 93 | if jobName := ctx.Request.URL.Query().Get("job"); jobName != "" { 94 | return db.Where("kind = ?", jobName) 95 | } 96 | 97 | if groupName := ctx.Request.URL.Query().Get("group"); groupName != "" { 98 | var jobNames []string 99 | for _, job := range worker.Jobs { 100 | if groupName == job.Group { 101 | jobNames = append(jobNames, job.Name) 102 | } 103 | } 104 | if len(jobNames) > 0 { 105 | return db.Where("kind IN (?)", jobNames) 106 | } 107 | return db.Where("kind IS NULL") 108 | } 109 | 110 | { 111 | var jobNames []string 112 | for _, job := range worker.Jobs { 113 | jobNames = append(jobNames, job.Name) 114 | } 115 | if len(jobNames) > 0 { 116 | return db.Where("kind IN (?)", jobNames) 117 | } 118 | } 119 | 120 | return db 121 | }, 122 | Default: true, 123 | }) 124 | 125 | // Auto Migration 126 | worker.Admin.DB.AutoMigrate(worker.Config.Job) 127 | 128 | // Configure jobs 129 | for _, job := range worker.Jobs { 130 | if job.Resource == nil { 131 | job.Resource = worker.Admin.NewResource(worker.JobResource.Value) 132 | } 133 | } 134 | } 135 | } 136 | 137 | // ConfigureQorResource a method used to config Worker for qor admin 138 | func (worker *Worker) ConfigureQorResource(res resource.Resourcer) { 139 | if res, ok := res.(*admin.Resource); ok { 140 | // Parse job 141 | cmdLine := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) 142 | qorJobID := cmdLine.String("qor-job", "", "Qor Job ID") 143 | runAnother := cmdLine.Bool("run-another", false, "Run another qor job") 144 | cmdLine.Parse(os.Args[1:]) 145 | worker.mounted = true 146 | 147 | if *qorJobID != "" { 148 | if *runAnother == true { 149 | if newJob := worker.saveAnotherJob(*qorJobID); newJob != nil { 150 | newJobID := newJob.GetJobID() 151 | qorJobID = &newJobID 152 | } else { 153 | fmt.Println("failed to clone job " + *qorJobID) 154 | os.Exit(1) 155 | } 156 | } 157 | 158 | if err := worker.RunJob(*qorJobID); err == nil { 159 | os.Exit(0) 160 | } else { 161 | fmt.Println(err) 162 | // os.Exit(1) 163 | } 164 | } 165 | 166 | // register view funcmaps 167 | worker.Admin.RegisterFuncMap("get_grouped_jobs", func(worker *Worker, context *admin.Context) map[string][]*Job { 168 | var groupedJobs = map[string][]*Job{} 169 | var groupName = context.Request.URL.Query().Get("group") 170 | var jobName = context.Request.URL.Query().Get("job") 171 | for _, job := range worker.Jobs { 172 | if !(job.HasPermission(roles.Read, context.Context) && job.HasPermission(roles.Create, context.Context)) { 173 | continue 174 | } 175 | 176 | if (groupName == "" || groupName == job.Group) && (jobName == "" || jobName == job.Name) { 177 | groupedJobs[job.Group] = append(groupedJobs[job.Group], job) 178 | } 179 | } 180 | return groupedJobs 181 | }) 182 | 183 | // configure routes 184 | router := worker.Admin.GetRouter() 185 | controller := workerController{Worker: worker} 186 | jobParamIDName := worker.JobResource.ParamIDName() 187 | 188 | router.Get(res.ToParam(), controller.Index, &admin.RouteConfig{Resource: worker.JobResource}) 189 | router.Get(res.ToParam()+"/new", controller.New, &admin.RouteConfig{Resource: worker.JobResource}) 190 | router.Get(fmt.Sprintf("%v/%v", res.ToParam(), jobParamIDName), controller.Show, &admin.RouteConfig{Resource: worker.JobResource}) 191 | router.Get(fmt.Sprintf("%v/%v/edit", res.ToParam(), jobParamIDName), controller.Show, &admin.RouteConfig{Resource: worker.JobResource}) 192 | router.Post(fmt.Sprintf("%v/%v/run", res.ToParam(), jobParamIDName), controller.RunJob, &admin.RouteConfig{Resource: worker.JobResource}) 193 | router.Post(res.ToParam(), controller.AddJob, &admin.RouteConfig{Resource: worker.JobResource}) 194 | router.Put(fmt.Sprintf("%v/%v", res.ToParam(), jobParamIDName), controller.Update, &admin.RouteConfig{Resource: worker.JobResource}) 195 | router.Delete(fmt.Sprintf("%v/%v", res.ToParam(), jobParamIDName), controller.KillJob, &admin.RouteConfig{Resource: worker.JobResource}) 196 | } 197 | } 198 | 199 | // SetQueue set worker's queue 200 | func (worker *Worker) SetQueue(queue Queue) { 201 | worker.Queue = queue 202 | } 203 | 204 | // RegisterJob register a job into Worker 205 | func (worker *Worker) RegisterJob(job *Job) error { 206 | if worker.mounted { 207 | debug.PrintStack() 208 | fmt.Printf("Job should be registered before Worker mounted into admin, but %v is registered after that", job.Name) 209 | } 210 | 211 | job.Worker = worker 212 | worker.Jobs = append(worker.Jobs, job) 213 | return nil 214 | } 215 | 216 | // GetRegisteredJob register a job into Worker 217 | func (worker *Worker) GetRegisteredJob(name string) *Job { 218 | for _, job := range worker.Jobs { 219 | if job.Name == name { 220 | return job 221 | } 222 | } 223 | return nil 224 | } 225 | 226 | // GetJob get job with id 227 | func (worker *Worker) GetJob(jobID string) (QorJobInterface, error) { 228 | qorJob := worker.JobResource.NewStruct().(QorJobInterface) 229 | 230 | context := worker.Admin.NewContext(nil, nil) 231 | context.ResourceID = jobID 232 | context.Resource = worker.JobResource 233 | 234 | if err := worker.JobResource.FindOneHandler(qorJob, nil, context.Context); err == nil { 235 | for _, job := range worker.Jobs { 236 | if job.Name == qorJob.GetJobName() { 237 | qorJob.SetJob(job) 238 | return qorJob, nil 239 | } 240 | } 241 | return nil, fmt.Errorf("failed to load job: %v, unregistered job type: %v", jobID, qorJob.GetJobName()) 242 | } 243 | return nil, fmt.Errorf("failed to find job: %v", jobID) 244 | } 245 | 246 | // AddJob add job to worker 247 | func (worker *Worker) AddJob(qorJob QorJobInterface) error { 248 | return worker.Queue.Add(qorJob) 249 | } 250 | 251 | // RunJob run job with job id 252 | func (worker *Worker) RunJob(jobID string) error { 253 | qorJob, err := worker.GetJob(jobID) 254 | 255 | if qorJob != nil && err == nil { 256 | defer func() { 257 | if r := recover(); r != nil { 258 | qorJob.AddLog(string(debug.Stack())) 259 | qorJob.SetProgressText(fmt.Sprint(r)) 260 | qorJob.SetStatus(JobStatusException) 261 | } 262 | }() 263 | 264 | if qorJob.GetStatus() != JobStatusNew && qorJob.GetStatus() != JobStatusScheduled { 265 | return errors.New("invalid job status, current status: " + qorJob.GetStatus()) 266 | } 267 | 268 | if err = qorJob.SetStatus(JobStatusRunning); err == nil { 269 | if err = qorJob.GetJob().GetQueue().Run(qorJob); err == nil { 270 | if len(qorJob.GetResultsTable().TableCells) > 0 { 271 | return qorJob.SetStatus(JobStatusException) 272 | } 273 | return qorJob.SetStatus(JobStatusDone) 274 | } 275 | 276 | qorJob.SetProgressText(err.Error()) 277 | qorJob.SetStatus(JobStatusException) 278 | } 279 | } 280 | 281 | return err 282 | } 283 | 284 | func (worker *Worker) saveAnotherJob(jobID string) QorJobInterface { 285 | jobResource := worker.JobResource 286 | newJob := jobResource.NewStruct().(QorJobInterface) 287 | 288 | job, err := worker.GetJob(jobID) 289 | if err == nil { 290 | newJob.SetJob(job.GetJob()) 291 | newJob.SetSerializableArgumentValue(job.GetArgument()) 292 | context := worker.Admin.NewContext(nil, nil) 293 | if err := jobResource.CallSave(newJob, context.Context); err == nil { 294 | return newJob 295 | } 296 | } 297 | return nil 298 | } 299 | 300 | // KillJob kill job with job id 301 | func (worker *Worker) KillJob(jobID string) error { 302 | if qorJob, err := worker.GetJob(jobID); err == nil { 303 | if qorJob.GetStatus() == JobStatusRunning { 304 | if err = qorJob.GetJob().GetQueue().Kill(qorJob); err == nil { 305 | qorJob.SetStatus(JobStatusKilled) 306 | return nil 307 | } 308 | return err 309 | } else if qorJob.GetStatus() == JobStatusScheduled || qorJob.GetStatus() == JobStatusNew { 310 | qorJob.SetStatus(JobStatusKilled) 311 | return worker.RemoveJob(jobID) 312 | } else { 313 | return errors.New("invalid job status") 314 | } 315 | } else { 316 | return err 317 | } 318 | } 319 | 320 | // RemoveJob remove job with job id 321 | func (worker *Worker) RemoveJob(jobID string) error { 322 | qorJob, err := worker.GetJob(jobID) 323 | if err == nil { 324 | return qorJob.GetJob().GetQueue().Remove(qorJob) 325 | } 326 | return err 327 | } 328 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@ampproject/remapping@^2.2.0": 6 | version "2.3.0" 7 | resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" 8 | integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== 9 | dependencies: 10 | "@jridgewell/gen-mapping" "^0.3.5" 11 | "@jridgewell/trace-mapping" "^0.3.24" 12 | 13 | "@babel/code-frame@^7.24.7": 14 | version "7.24.7" 15 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" 16 | integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== 17 | dependencies: 18 | "@babel/highlight" "^7.24.7" 19 | picocolors "^1.0.0" 20 | 21 | "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.24.8", "@babel/compat-data@^7.25.0": 22 | version "7.25.0" 23 | resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.0.tgz#6b226a5da3a686db3c30519750e071dce292ad95" 24 | integrity sha512-P4fwKI2mjEb3ZU5cnMJzvRsRKGBUcs8jvxIoRmr6ufAY9Xk2Bz7JubRTTivkw55c7WQJfTECeqYVa+HZ0FzREg== 25 | 26 | "@babel/core@^7.24.9": 27 | version "7.24.9" 28 | resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.9.tgz#dc07c9d307162c97fa9484ea997ade65841c7c82" 29 | integrity sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg== 30 | dependencies: 31 | "@ampproject/remapping" "^2.2.0" 32 | "@babel/code-frame" "^7.24.7" 33 | "@babel/generator" "^7.24.9" 34 | "@babel/helper-compilation-targets" "^7.24.8" 35 | "@babel/helper-module-transforms" "^7.24.9" 36 | "@babel/helpers" "^7.24.8" 37 | "@babel/parser" "^7.24.8" 38 | "@babel/template" "^7.24.7" 39 | "@babel/traverse" "^7.24.8" 40 | "@babel/types" "^7.24.9" 41 | convert-source-map "^2.0.0" 42 | debug "^4.1.0" 43 | gensync "^1.0.0-beta.2" 44 | json5 "^2.2.3" 45 | semver "^6.3.1" 46 | 47 | "@babel/generator@^7.24.9", "@babel/generator@^7.25.0": 48 | version "7.25.0" 49 | resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e" 50 | integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw== 51 | dependencies: 52 | "@babel/types" "^7.25.0" 53 | "@jridgewell/gen-mapping" "^0.3.5" 54 | "@jridgewell/trace-mapping" "^0.3.25" 55 | jsesc "^2.5.1" 56 | 57 | "@babel/helper-annotate-as-pure@^7.24.7": 58 | version "7.24.7" 59 | resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz#5373c7bc8366b12a033b4be1ac13a206c6656aab" 60 | integrity sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg== 61 | dependencies: 62 | "@babel/types" "^7.24.7" 63 | 64 | "@babel/helper-builder-binary-assignment-operator-visitor@^7.24.7": 65 | version "7.24.7" 66 | resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz#37d66feb012024f2422b762b9b2a7cfe27c7fba3" 67 | integrity sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA== 68 | dependencies: 69 | "@babel/traverse" "^7.24.7" 70 | "@babel/types" "^7.24.7" 71 | 72 | "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.24.7", "@babel/helper-compilation-targets@^7.24.8": 73 | version "7.24.8" 74 | resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz#b607c3161cd9d1744977d4f97139572fe778c271" 75 | integrity sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw== 76 | dependencies: 77 | "@babel/compat-data" "^7.24.8" 78 | "@babel/helper-validator-option" "^7.24.8" 79 | browserslist "^4.23.1" 80 | lru-cache "^5.1.1" 81 | semver "^6.3.1" 82 | 83 | "@babel/helper-create-class-features-plugin@^7.24.7": 84 | version "7.25.0" 85 | resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz#a109bf9c3d58dfed83aaf42e85633c89f43a6253" 86 | integrity sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ== 87 | dependencies: 88 | "@babel/helper-annotate-as-pure" "^7.24.7" 89 | "@babel/helper-member-expression-to-functions" "^7.24.8" 90 | "@babel/helper-optimise-call-expression" "^7.24.7" 91 | "@babel/helper-replace-supers" "^7.25.0" 92 | "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" 93 | "@babel/traverse" "^7.25.0" 94 | semver "^6.3.1" 95 | 96 | "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.24.7", "@babel/helper-create-regexp-features-plugin@^7.25.0": 97 | version "7.25.0" 98 | resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.0.tgz#17afe5d23b3a833a90f0fab9c2ae69fea192de5c" 99 | integrity sha512-q0T+dknZS+L5LDazIP+02gEZITG5unzvb6yIjcmj5i0eFrs5ToBV2m2JGH4EsE/gtP8ygEGLGApBgRIZkTm7zg== 100 | dependencies: 101 | "@babel/helper-annotate-as-pure" "^7.24.7" 102 | regexpu-core "^5.3.1" 103 | semver "^6.3.1" 104 | 105 | "@babel/helper-define-polyfill-provider@^0.6.1", "@babel/helper-define-polyfill-provider@^0.6.2": 106 | version "0.6.2" 107 | resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" 108 | integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== 109 | dependencies: 110 | "@babel/helper-compilation-targets" "^7.22.6" 111 | "@babel/helper-plugin-utils" "^7.22.5" 112 | debug "^4.1.1" 113 | lodash.debounce "^4.0.8" 114 | resolve "^1.14.2" 115 | 116 | "@babel/helper-member-expression-to-functions@^7.24.8": 117 | version "7.24.8" 118 | resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz#6155e079c913357d24a4c20480db7c712a5c3fb6" 119 | integrity sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA== 120 | dependencies: 121 | "@babel/traverse" "^7.24.8" 122 | "@babel/types" "^7.24.8" 123 | 124 | "@babel/helper-module-imports@^7.24.7": 125 | version "7.24.7" 126 | resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" 127 | integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== 128 | dependencies: 129 | "@babel/traverse" "^7.24.7" 130 | "@babel/types" "^7.24.7" 131 | 132 | "@babel/helper-module-transforms@^7.24.7", "@babel/helper-module-transforms@^7.24.8", "@babel/helper-module-transforms@^7.24.9", "@babel/helper-module-transforms@^7.25.0": 133 | version "7.25.0" 134 | resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.0.tgz#3ffc23c473a2769a7e40d3274495bd559fdd2ecc" 135 | integrity sha512-bIkOa2ZJYn7FHnepzr5iX9Kmz8FjIz4UKzJ9zhX3dnYuVW0xul9RuR3skBfoLu+FPTQw90EHW9rJsSZhyLQ3fQ== 136 | dependencies: 137 | "@babel/helper-module-imports" "^7.24.7" 138 | "@babel/helper-simple-access" "^7.24.7" 139 | "@babel/helper-validator-identifier" "^7.24.7" 140 | "@babel/traverse" "^7.25.0" 141 | 142 | "@babel/helper-optimise-call-expression@^7.24.7": 143 | version "7.24.7" 144 | resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz#8b0a0456c92f6b323d27cfd00d1d664e76692a0f" 145 | integrity sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A== 146 | dependencies: 147 | "@babel/types" "^7.24.7" 148 | 149 | "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": 150 | version "7.24.8" 151 | resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" 152 | integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== 153 | 154 | "@babel/helper-remap-async-to-generator@^7.24.7", "@babel/helper-remap-async-to-generator@^7.25.0": 155 | version "7.25.0" 156 | resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz#d2f0fbba059a42d68e5e378feaf181ef6055365e" 157 | integrity sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw== 158 | dependencies: 159 | "@babel/helper-annotate-as-pure" "^7.24.7" 160 | "@babel/helper-wrap-function" "^7.25.0" 161 | "@babel/traverse" "^7.25.0" 162 | 163 | "@babel/helper-replace-supers@^7.24.7", "@babel/helper-replace-supers@^7.25.0": 164 | version "7.25.0" 165 | resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz#ff44deac1c9f619523fe2ca1fd650773792000a9" 166 | integrity sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg== 167 | dependencies: 168 | "@babel/helper-member-expression-to-functions" "^7.24.8" 169 | "@babel/helper-optimise-call-expression" "^7.24.7" 170 | "@babel/traverse" "^7.25.0" 171 | 172 | "@babel/helper-simple-access@^7.24.7": 173 | version "7.24.7" 174 | resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" 175 | integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== 176 | dependencies: 177 | "@babel/traverse" "^7.24.7" 178 | "@babel/types" "^7.24.7" 179 | 180 | "@babel/helper-skip-transparent-expression-wrappers@^7.24.7": 181 | version "7.24.7" 182 | resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz#5f8fa83b69ed5c27adc56044f8be2b3ea96669d9" 183 | integrity sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ== 184 | dependencies: 185 | "@babel/traverse" "^7.24.7" 186 | "@babel/types" "^7.24.7" 187 | 188 | "@babel/helper-string-parser@^7.24.8": 189 | version "7.24.8" 190 | resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" 191 | integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== 192 | 193 | "@babel/helper-validator-identifier@^7.24.7": 194 | version "7.24.7" 195 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" 196 | integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== 197 | 198 | "@babel/helper-validator-option@^7.24.8": 199 | version "7.24.8" 200 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" 201 | integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== 202 | 203 | "@babel/helper-wrap-function@^7.25.0": 204 | version "7.25.0" 205 | resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz#dab12f0f593d6ca48c0062c28bcfb14ebe812f81" 206 | integrity sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ== 207 | dependencies: 208 | "@babel/template" "^7.25.0" 209 | "@babel/traverse" "^7.25.0" 210 | "@babel/types" "^7.25.0" 211 | 212 | "@babel/helpers@^7.24.8": 213 | version "7.25.0" 214 | resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.0.tgz#e69beb7841cb93a6505531ede34f34e6a073650a" 215 | integrity sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw== 216 | dependencies: 217 | "@babel/template" "^7.25.0" 218 | "@babel/types" "^7.25.0" 219 | 220 | "@babel/highlight@^7.24.7": 221 | version "7.24.7" 222 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" 223 | integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== 224 | dependencies: 225 | "@babel/helper-validator-identifier" "^7.24.7" 226 | chalk "^2.4.2" 227 | js-tokens "^4.0.0" 228 | picocolors "^1.0.0" 229 | 230 | "@babel/parser@^7.24.8", "@babel/parser@^7.25.0": 231 | version "7.25.0" 232 | resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.0.tgz#9fdc9237504d797b6e7b8f66e78ea7f570d256ad" 233 | integrity sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA== 234 | 235 | "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.0": 236 | version "7.25.0" 237 | resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.0.tgz#328275f22d809b962978d998c6eba22a233ac8aa" 238 | integrity sha512-dG0aApncVQwAUJa8tP1VHTnmU67BeIQvKafd3raEx315H54FfkZSz3B/TT+33ZQAjatGJA79gZqTtqL5QZUKXw== 239 | dependencies: 240 | "@babel/helper-plugin-utils" "^7.24.8" 241 | "@babel/traverse" "^7.25.0" 242 | 243 | "@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.0": 244 | version "7.25.0" 245 | resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz#cd0c583e01369ef51676bdb3d7b603e17d2b3f73" 246 | integrity sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA== 247 | dependencies: 248 | "@babel/helper-plugin-utils" "^7.24.8" 249 | 250 | "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.0": 251 | version "7.25.0" 252 | resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz#749bde80356b295390954643de7635e0dffabe73" 253 | integrity sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA== 254 | dependencies: 255 | "@babel/helper-plugin-utils" "^7.24.8" 256 | 257 | "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.24.7": 258 | version "7.24.7" 259 | resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz#e4eabdd5109acc399b38d7999b2ef66fc2022f89" 260 | integrity sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ== 261 | dependencies: 262 | "@babel/helper-plugin-utils" "^7.24.7" 263 | "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" 264 | "@babel/plugin-transform-optional-chaining" "^7.24.7" 265 | 266 | "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.0": 267 | version "7.25.0" 268 | resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz#3a82a70e7cb7294ad2559465ebcb871dfbf078fb" 269 | integrity sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw== 270 | dependencies: 271 | "@babel/helper-plugin-utils" "^7.24.8" 272 | "@babel/traverse" "^7.25.0" 273 | 274 | "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": 275 | version "7.21.0-placeholder-for-preset-env.2" 276 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" 277 | integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== 278 | 279 | "@babel/plugin-syntax-async-generators@^7.8.4": 280 | version "7.8.4" 281 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" 282 | integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== 283 | dependencies: 284 | "@babel/helper-plugin-utils" "^7.8.0" 285 | 286 | "@babel/plugin-syntax-class-properties@^7.12.13": 287 | version "7.12.13" 288 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" 289 | integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== 290 | dependencies: 291 | "@babel/helper-plugin-utils" "^7.12.13" 292 | 293 | "@babel/plugin-syntax-class-static-block@^7.14.5": 294 | version "7.14.5" 295 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" 296 | integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== 297 | dependencies: 298 | "@babel/helper-plugin-utils" "^7.14.5" 299 | 300 | "@babel/plugin-syntax-dynamic-import@^7.8.3": 301 | version "7.8.3" 302 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" 303 | integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== 304 | dependencies: 305 | "@babel/helper-plugin-utils" "^7.8.0" 306 | 307 | "@babel/plugin-syntax-export-namespace-from@^7.8.3": 308 | version "7.8.3" 309 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" 310 | integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== 311 | dependencies: 312 | "@babel/helper-plugin-utils" "^7.8.3" 313 | 314 | "@babel/plugin-syntax-import-assertions@^7.24.7": 315 | version "7.24.7" 316 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz#2a0b406b5871a20a841240586b1300ce2088a778" 317 | integrity sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg== 318 | dependencies: 319 | "@babel/helper-plugin-utils" "^7.24.7" 320 | 321 | "@babel/plugin-syntax-import-attributes@^7.24.7": 322 | version "7.24.7" 323 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz#b4f9ea95a79e6912480c4b626739f86a076624ca" 324 | integrity sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A== 325 | dependencies: 326 | "@babel/helper-plugin-utils" "^7.24.7" 327 | 328 | "@babel/plugin-syntax-import-meta@^7.10.4": 329 | version "7.10.4" 330 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" 331 | integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== 332 | dependencies: 333 | "@babel/helper-plugin-utils" "^7.10.4" 334 | 335 | "@babel/plugin-syntax-json-strings@^7.8.3": 336 | version "7.8.3" 337 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" 338 | integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== 339 | dependencies: 340 | "@babel/helper-plugin-utils" "^7.8.0" 341 | 342 | "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": 343 | version "7.10.4" 344 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" 345 | integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== 346 | dependencies: 347 | "@babel/helper-plugin-utils" "^7.10.4" 348 | 349 | "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": 350 | version "7.8.3" 351 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" 352 | integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== 353 | dependencies: 354 | "@babel/helper-plugin-utils" "^7.8.0" 355 | 356 | "@babel/plugin-syntax-numeric-separator@^7.10.4": 357 | version "7.10.4" 358 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" 359 | integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== 360 | dependencies: 361 | "@babel/helper-plugin-utils" "^7.10.4" 362 | 363 | "@babel/plugin-syntax-object-rest-spread@^7.8.3": 364 | version "7.8.3" 365 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" 366 | integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== 367 | dependencies: 368 | "@babel/helper-plugin-utils" "^7.8.0" 369 | 370 | "@babel/plugin-syntax-optional-catch-binding@^7.8.3": 371 | version "7.8.3" 372 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" 373 | integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== 374 | dependencies: 375 | "@babel/helper-plugin-utils" "^7.8.0" 376 | 377 | "@babel/plugin-syntax-optional-chaining@^7.8.3": 378 | version "7.8.3" 379 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" 380 | integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== 381 | dependencies: 382 | "@babel/helper-plugin-utils" "^7.8.0" 383 | 384 | "@babel/plugin-syntax-private-property-in-object@^7.14.5": 385 | version "7.14.5" 386 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" 387 | integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== 388 | dependencies: 389 | "@babel/helper-plugin-utils" "^7.14.5" 390 | 391 | "@babel/plugin-syntax-top-level-await@^7.14.5": 392 | version "7.14.5" 393 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" 394 | integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== 395 | dependencies: 396 | "@babel/helper-plugin-utils" "^7.14.5" 397 | 398 | "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": 399 | version "7.18.6" 400 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" 401 | integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== 402 | dependencies: 403 | "@babel/helper-create-regexp-features-plugin" "^7.18.6" 404 | "@babel/helper-plugin-utils" "^7.18.6" 405 | 406 | "@babel/plugin-transform-arrow-functions@^7.24.7": 407 | version "7.24.7" 408 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz#4f6886c11e423bd69f3ce51dbf42424a5f275514" 409 | integrity sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ== 410 | dependencies: 411 | "@babel/helper-plugin-utils" "^7.24.7" 412 | 413 | "@babel/plugin-transform-async-generator-functions@^7.25.0": 414 | version "7.25.0" 415 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz#b785cf35d73437f6276b1e30439a57a50747bddf" 416 | integrity sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q== 417 | dependencies: 418 | "@babel/helper-plugin-utils" "^7.24.8" 419 | "@babel/helper-remap-async-to-generator" "^7.25.0" 420 | "@babel/plugin-syntax-async-generators" "^7.8.4" 421 | "@babel/traverse" "^7.25.0" 422 | 423 | "@babel/plugin-transform-async-to-generator@^7.24.7": 424 | version "7.24.7" 425 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz#72a3af6c451d575842a7e9b5a02863414355bdcc" 426 | integrity sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA== 427 | dependencies: 428 | "@babel/helper-module-imports" "^7.24.7" 429 | "@babel/helper-plugin-utils" "^7.24.7" 430 | "@babel/helper-remap-async-to-generator" "^7.24.7" 431 | 432 | "@babel/plugin-transform-block-scoped-functions@^7.24.7": 433 | version "7.24.7" 434 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz#a4251d98ea0c0f399dafe1a35801eaba455bbf1f" 435 | integrity sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ== 436 | dependencies: 437 | "@babel/helper-plugin-utils" "^7.24.7" 438 | 439 | "@babel/plugin-transform-block-scoping@^7.25.0": 440 | version "7.25.0" 441 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz#23a6ed92e6b006d26b1869b1c91d1b917c2ea2ac" 442 | integrity sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ== 443 | dependencies: 444 | "@babel/helper-plugin-utils" "^7.24.8" 445 | 446 | "@babel/plugin-transform-class-properties@^7.24.7": 447 | version "7.24.7" 448 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz#256879467b57b0b68c7ddfc5b76584f398cd6834" 449 | integrity sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w== 450 | dependencies: 451 | "@babel/helper-create-class-features-plugin" "^7.24.7" 452 | "@babel/helper-plugin-utils" "^7.24.7" 453 | 454 | "@babel/plugin-transform-class-static-block@^7.24.7": 455 | version "7.24.7" 456 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz#c82027ebb7010bc33c116d4b5044fbbf8c05484d" 457 | integrity sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ== 458 | dependencies: 459 | "@babel/helper-create-class-features-plugin" "^7.24.7" 460 | "@babel/helper-plugin-utils" "^7.24.7" 461 | "@babel/plugin-syntax-class-static-block" "^7.14.5" 462 | 463 | "@babel/plugin-transform-classes@^7.25.0": 464 | version "7.25.0" 465 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz#63122366527d88e0ef61b612554fe3f8c793991e" 466 | integrity sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw== 467 | dependencies: 468 | "@babel/helper-annotate-as-pure" "^7.24.7" 469 | "@babel/helper-compilation-targets" "^7.24.8" 470 | "@babel/helper-plugin-utils" "^7.24.8" 471 | "@babel/helper-replace-supers" "^7.25.0" 472 | "@babel/traverse" "^7.25.0" 473 | globals "^11.1.0" 474 | 475 | "@babel/plugin-transform-computed-properties@^7.24.7": 476 | version "7.24.7" 477 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz#4cab3214e80bc71fae3853238d13d097b004c707" 478 | integrity sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ== 479 | dependencies: 480 | "@babel/helper-plugin-utils" "^7.24.7" 481 | "@babel/template" "^7.24.7" 482 | 483 | "@babel/plugin-transform-destructuring@^7.24.8": 484 | version "7.24.8" 485 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz#c828e814dbe42a2718a838c2a2e16a408e055550" 486 | integrity sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ== 487 | dependencies: 488 | "@babel/helper-plugin-utils" "^7.24.8" 489 | 490 | "@babel/plugin-transform-dotall-regex@^7.24.7": 491 | version "7.24.7" 492 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz#5f8bf8a680f2116a7207e16288a5f974ad47a7a0" 493 | integrity sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw== 494 | dependencies: 495 | "@babel/helper-create-regexp-features-plugin" "^7.24.7" 496 | "@babel/helper-plugin-utils" "^7.24.7" 497 | 498 | "@babel/plugin-transform-duplicate-keys@^7.24.7": 499 | version "7.24.7" 500 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz#dd20102897c9a2324e5adfffb67ff3610359a8ee" 501 | integrity sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw== 502 | dependencies: 503 | "@babel/helper-plugin-utils" "^7.24.7" 504 | 505 | "@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.0": 506 | version "7.25.0" 507 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz#809af7e3339466b49c034c683964ee8afb3e2604" 508 | integrity sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g== 509 | dependencies: 510 | "@babel/helper-create-regexp-features-plugin" "^7.25.0" 511 | "@babel/helper-plugin-utils" "^7.24.8" 512 | 513 | "@babel/plugin-transform-dynamic-import@^7.24.7": 514 | version "7.24.7" 515 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz#4d8b95e3bae2b037673091aa09cd33fecd6419f4" 516 | integrity sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg== 517 | dependencies: 518 | "@babel/helper-plugin-utils" "^7.24.7" 519 | "@babel/plugin-syntax-dynamic-import" "^7.8.3" 520 | 521 | "@babel/plugin-transform-exponentiation-operator@^7.24.7": 522 | version "7.24.7" 523 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz#b629ee22645f412024297d5245bce425c31f9b0d" 524 | integrity sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ== 525 | dependencies: 526 | "@babel/helper-builder-binary-assignment-operator-visitor" "^7.24.7" 527 | "@babel/helper-plugin-utils" "^7.24.7" 528 | 529 | "@babel/plugin-transform-export-namespace-from@^7.24.7": 530 | version "7.24.7" 531 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz#176d52d8d8ed516aeae7013ee9556d540c53f197" 532 | integrity sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA== 533 | dependencies: 534 | "@babel/helper-plugin-utils" "^7.24.7" 535 | "@babel/plugin-syntax-export-namespace-from" "^7.8.3" 536 | 537 | "@babel/plugin-transform-for-of@^7.24.7": 538 | version "7.24.7" 539 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz#f25b33f72df1d8be76399e1b8f3f9d366eb5bc70" 540 | integrity sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g== 541 | dependencies: 542 | "@babel/helper-plugin-utils" "^7.24.7" 543 | "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" 544 | 545 | "@babel/plugin-transform-function-name@^7.25.0": 546 | version "7.25.1" 547 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz#b85e773097526c1a4fc4ba27322748643f26fc37" 548 | integrity sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA== 549 | dependencies: 550 | "@babel/helper-compilation-targets" "^7.24.8" 551 | "@babel/helper-plugin-utils" "^7.24.8" 552 | "@babel/traverse" "^7.25.1" 553 | 554 | "@babel/plugin-transform-json-strings@^7.24.7": 555 | version "7.24.7" 556 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz#f3e9c37c0a373fee86e36880d45b3664cedaf73a" 557 | integrity sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw== 558 | dependencies: 559 | "@babel/helper-plugin-utils" "^7.24.7" 560 | "@babel/plugin-syntax-json-strings" "^7.8.3" 561 | 562 | "@babel/plugin-transform-literals@^7.24.7": 563 | version "7.24.7" 564 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz#36b505c1e655151a9d7607799a9988fc5467d06c" 565 | integrity sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ== 566 | dependencies: 567 | "@babel/helper-plugin-utils" "^7.24.7" 568 | 569 | "@babel/plugin-transform-logical-assignment-operators@^7.24.7": 570 | version "7.24.7" 571 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz#a58fb6eda16c9dc8f9ff1c7b1ba6deb7f4694cb0" 572 | integrity sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw== 573 | dependencies: 574 | "@babel/helper-plugin-utils" "^7.24.7" 575 | "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" 576 | 577 | "@babel/plugin-transform-member-expression-literals@^7.24.7": 578 | version "7.24.7" 579 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz#3b4454fb0e302e18ba4945ba3246acb1248315df" 580 | integrity sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw== 581 | dependencies: 582 | "@babel/helper-plugin-utils" "^7.24.7" 583 | 584 | "@babel/plugin-transform-modules-amd@^7.24.7": 585 | version "7.24.7" 586 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz#65090ed493c4a834976a3ca1cde776e6ccff32d7" 587 | integrity sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg== 588 | dependencies: 589 | "@babel/helper-module-transforms" "^7.24.7" 590 | "@babel/helper-plugin-utils" "^7.24.7" 591 | 592 | "@babel/plugin-transform-modules-commonjs@^7.24.8": 593 | version "7.24.8" 594 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz#ab6421e564b717cb475d6fff70ae7f103536ea3c" 595 | integrity sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA== 596 | dependencies: 597 | "@babel/helper-module-transforms" "^7.24.8" 598 | "@babel/helper-plugin-utils" "^7.24.8" 599 | "@babel/helper-simple-access" "^7.24.7" 600 | 601 | "@babel/plugin-transform-modules-systemjs@^7.25.0": 602 | version "7.25.0" 603 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz#8f46cdc5f9e5af74f3bd019485a6cbe59685ea33" 604 | integrity sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw== 605 | dependencies: 606 | "@babel/helper-module-transforms" "^7.25.0" 607 | "@babel/helper-plugin-utils" "^7.24.8" 608 | "@babel/helper-validator-identifier" "^7.24.7" 609 | "@babel/traverse" "^7.25.0" 610 | 611 | "@babel/plugin-transform-modules-umd@^7.24.7": 612 | version "7.24.7" 613 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz#edd9f43ec549099620df7df24e7ba13b5c76efc8" 614 | integrity sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A== 615 | dependencies: 616 | "@babel/helper-module-transforms" "^7.24.7" 617 | "@babel/helper-plugin-utils" "^7.24.7" 618 | 619 | "@babel/plugin-transform-named-capturing-groups-regex@^7.24.7": 620 | version "7.24.7" 621 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz#9042e9b856bc6b3688c0c2e4060e9e10b1460923" 622 | integrity sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g== 623 | dependencies: 624 | "@babel/helper-create-regexp-features-plugin" "^7.24.7" 625 | "@babel/helper-plugin-utils" "^7.24.7" 626 | 627 | "@babel/plugin-transform-new-target@^7.24.7": 628 | version "7.24.7" 629 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz#31ff54c4e0555cc549d5816e4ab39241dfb6ab00" 630 | integrity sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA== 631 | dependencies: 632 | "@babel/helper-plugin-utils" "^7.24.7" 633 | 634 | "@babel/plugin-transform-nullish-coalescing-operator@^7.24.7": 635 | version "7.24.7" 636 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz#1de4534c590af9596f53d67f52a92f12db984120" 637 | integrity sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ== 638 | dependencies: 639 | "@babel/helper-plugin-utils" "^7.24.7" 640 | "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" 641 | 642 | "@babel/plugin-transform-numeric-separator@^7.24.7": 643 | version "7.24.7" 644 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz#bea62b538c80605d8a0fac9b40f48e97efa7de63" 645 | integrity sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA== 646 | dependencies: 647 | "@babel/helper-plugin-utils" "^7.24.7" 648 | "@babel/plugin-syntax-numeric-separator" "^7.10.4" 649 | 650 | "@babel/plugin-transform-object-rest-spread@^7.24.7": 651 | version "7.24.7" 652 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz#d13a2b93435aeb8a197e115221cab266ba6e55d6" 653 | integrity sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q== 654 | dependencies: 655 | "@babel/helper-compilation-targets" "^7.24.7" 656 | "@babel/helper-plugin-utils" "^7.24.7" 657 | "@babel/plugin-syntax-object-rest-spread" "^7.8.3" 658 | "@babel/plugin-transform-parameters" "^7.24.7" 659 | 660 | "@babel/plugin-transform-object-super@^7.24.7": 661 | version "7.24.7" 662 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz#66eeaff7830bba945dd8989b632a40c04ed625be" 663 | integrity sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg== 664 | dependencies: 665 | "@babel/helper-plugin-utils" "^7.24.7" 666 | "@babel/helper-replace-supers" "^7.24.7" 667 | 668 | "@babel/plugin-transform-optional-catch-binding@^7.24.7": 669 | version "7.24.7" 670 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz#00eabd883d0dd6a60c1c557548785919b6e717b4" 671 | integrity sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA== 672 | dependencies: 673 | "@babel/helper-plugin-utils" "^7.24.7" 674 | "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" 675 | 676 | "@babel/plugin-transform-optional-chaining@^7.24.7", "@babel/plugin-transform-optional-chaining@^7.24.8": 677 | version "7.24.8" 678 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz#bb02a67b60ff0406085c13d104c99a835cdf365d" 679 | integrity sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw== 680 | dependencies: 681 | "@babel/helper-plugin-utils" "^7.24.8" 682 | "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" 683 | "@babel/plugin-syntax-optional-chaining" "^7.8.3" 684 | 685 | "@babel/plugin-transform-parameters@^7.24.7": 686 | version "7.24.7" 687 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz#5881f0ae21018400e320fc7eb817e529d1254b68" 688 | integrity sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA== 689 | dependencies: 690 | "@babel/helper-plugin-utils" "^7.24.7" 691 | 692 | "@babel/plugin-transform-private-methods@^7.24.7": 693 | version "7.24.7" 694 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz#e6318746b2ae70a59d023d5cc1344a2ba7a75f5e" 695 | integrity sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ== 696 | dependencies: 697 | "@babel/helper-create-class-features-plugin" "^7.24.7" 698 | "@babel/helper-plugin-utils" "^7.24.7" 699 | 700 | "@babel/plugin-transform-private-property-in-object@^7.24.7": 701 | version "7.24.7" 702 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz#4eec6bc701288c1fab5f72e6a4bbc9d67faca061" 703 | integrity sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA== 704 | dependencies: 705 | "@babel/helper-annotate-as-pure" "^7.24.7" 706 | "@babel/helper-create-class-features-plugin" "^7.24.7" 707 | "@babel/helper-plugin-utils" "^7.24.7" 708 | "@babel/plugin-syntax-private-property-in-object" "^7.14.5" 709 | 710 | "@babel/plugin-transform-property-literals@^7.24.7": 711 | version "7.24.7" 712 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz#f0d2ed8380dfbed949c42d4d790266525d63bbdc" 713 | integrity sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA== 714 | dependencies: 715 | "@babel/helper-plugin-utils" "^7.24.7" 716 | 717 | "@babel/plugin-transform-regenerator@^7.24.7": 718 | version "7.24.7" 719 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz#021562de4534d8b4b1851759fd7af4e05d2c47f8" 720 | integrity sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA== 721 | dependencies: 722 | "@babel/helper-plugin-utils" "^7.24.7" 723 | regenerator-transform "^0.15.2" 724 | 725 | "@babel/plugin-transform-reserved-words@^7.24.7": 726 | version "7.24.7" 727 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz#80037fe4fbf031fc1125022178ff3938bb3743a4" 728 | integrity sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ== 729 | dependencies: 730 | "@babel/helper-plugin-utils" "^7.24.7" 731 | 732 | "@babel/plugin-transform-shorthand-properties@^7.24.7": 733 | version "7.24.7" 734 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz#85448c6b996e122fa9e289746140aaa99da64e73" 735 | integrity sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA== 736 | dependencies: 737 | "@babel/helper-plugin-utils" "^7.24.7" 738 | 739 | "@babel/plugin-transform-spread@^7.24.7": 740 | version "7.24.7" 741 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz#e8a38c0fde7882e0fb8f160378f74bd885cc7bb3" 742 | integrity sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng== 743 | dependencies: 744 | "@babel/helper-plugin-utils" "^7.24.7" 745 | "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" 746 | 747 | "@babel/plugin-transform-sticky-regex@^7.24.7": 748 | version "7.24.7" 749 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz#96ae80d7a7e5251f657b5cf18f1ea6bf926f5feb" 750 | integrity sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g== 751 | dependencies: 752 | "@babel/helper-plugin-utils" "^7.24.7" 753 | 754 | "@babel/plugin-transform-template-literals@^7.24.7": 755 | version "7.24.7" 756 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz#a05debb4a9072ae8f985bcf77f3f215434c8f8c8" 757 | integrity sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw== 758 | dependencies: 759 | "@babel/helper-plugin-utils" "^7.24.7" 760 | 761 | "@babel/plugin-transform-typeof-symbol@^7.24.8": 762 | version "7.24.8" 763 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz#383dab37fb073f5bfe6e60c654caac309f92ba1c" 764 | integrity sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw== 765 | dependencies: 766 | "@babel/helper-plugin-utils" "^7.24.8" 767 | 768 | "@babel/plugin-transform-unicode-escapes@^7.24.7": 769 | version "7.24.7" 770 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz#2023a82ced1fb4971630a2e079764502c4148e0e" 771 | integrity sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw== 772 | dependencies: 773 | "@babel/helper-plugin-utils" "^7.24.7" 774 | 775 | "@babel/plugin-transform-unicode-property-regex@^7.24.7": 776 | version "7.24.7" 777 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz#9073a4cd13b86ea71c3264659590ac086605bbcd" 778 | integrity sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w== 779 | dependencies: 780 | "@babel/helper-create-regexp-features-plugin" "^7.24.7" 781 | "@babel/helper-plugin-utils" "^7.24.7" 782 | 783 | "@babel/plugin-transform-unicode-regex@^7.24.7": 784 | version "7.24.7" 785 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz#dfc3d4a51127108099b19817c0963be6a2adf19f" 786 | integrity sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg== 787 | dependencies: 788 | "@babel/helper-create-regexp-features-plugin" "^7.24.7" 789 | "@babel/helper-plugin-utils" "^7.24.7" 790 | 791 | "@babel/plugin-transform-unicode-sets-regex@^7.24.7": 792 | version "7.24.7" 793 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz#d40705d67523803a576e29c63cef6e516b858ed9" 794 | integrity sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg== 795 | dependencies: 796 | "@babel/helper-create-regexp-features-plugin" "^7.24.7" 797 | "@babel/helper-plugin-utils" "^7.24.7" 798 | 799 | "@babel/preset-env@^7.25.0": 800 | version "7.25.0" 801 | resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.25.0.tgz#3fe92e470311e91478129efda101816c680f0479" 802 | integrity sha512-vYAA8PrCOeZfG4D87hmw1KJ1BPubghXP1e2MacRFwECGNKL76dkA38JEwYllbvQCpf/kLxsTtir0b8MtxKoVCw== 803 | dependencies: 804 | "@babel/compat-data" "^7.25.0" 805 | "@babel/helper-compilation-targets" "^7.24.8" 806 | "@babel/helper-plugin-utils" "^7.24.8" 807 | "@babel/helper-validator-option" "^7.24.8" 808 | "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.0" 809 | "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.0" 810 | "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.0" 811 | "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.7" 812 | "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.0" 813 | "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" 814 | "@babel/plugin-syntax-async-generators" "^7.8.4" 815 | "@babel/plugin-syntax-class-properties" "^7.12.13" 816 | "@babel/plugin-syntax-class-static-block" "^7.14.5" 817 | "@babel/plugin-syntax-dynamic-import" "^7.8.3" 818 | "@babel/plugin-syntax-export-namespace-from" "^7.8.3" 819 | "@babel/plugin-syntax-import-assertions" "^7.24.7" 820 | "@babel/plugin-syntax-import-attributes" "^7.24.7" 821 | "@babel/plugin-syntax-import-meta" "^7.10.4" 822 | "@babel/plugin-syntax-json-strings" "^7.8.3" 823 | "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" 824 | "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" 825 | "@babel/plugin-syntax-numeric-separator" "^7.10.4" 826 | "@babel/plugin-syntax-object-rest-spread" "^7.8.3" 827 | "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" 828 | "@babel/plugin-syntax-optional-chaining" "^7.8.3" 829 | "@babel/plugin-syntax-private-property-in-object" "^7.14.5" 830 | "@babel/plugin-syntax-top-level-await" "^7.14.5" 831 | "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" 832 | "@babel/plugin-transform-arrow-functions" "^7.24.7" 833 | "@babel/plugin-transform-async-generator-functions" "^7.25.0" 834 | "@babel/plugin-transform-async-to-generator" "^7.24.7" 835 | "@babel/plugin-transform-block-scoped-functions" "^7.24.7" 836 | "@babel/plugin-transform-block-scoping" "^7.25.0" 837 | "@babel/plugin-transform-class-properties" "^7.24.7" 838 | "@babel/plugin-transform-class-static-block" "^7.24.7" 839 | "@babel/plugin-transform-classes" "^7.25.0" 840 | "@babel/plugin-transform-computed-properties" "^7.24.7" 841 | "@babel/plugin-transform-destructuring" "^7.24.8" 842 | "@babel/plugin-transform-dotall-regex" "^7.24.7" 843 | "@babel/plugin-transform-duplicate-keys" "^7.24.7" 844 | "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.0" 845 | "@babel/plugin-transform-dynamic-import" "^7.24.7" 846 | "@babel/plugin-transform-exponentiation-operator" "^7.24.7" 847 | "@babel/plugin-transform-export-namespace-from" "^7.24.7" 848 | "@babel/plugin-transform-for-of" "^7.24.7" 849 | "@babel/plugin-transform-function-name" "^7.25.0" 850 | "@babel/plugin-transform-json-strings" "^7.24.7" 851 | "@babel/plugin-transform-literals" "^7.24.7" 852 | "@babel/plugin-transform-logical-assignment-operators" "^7.24.7" 853 | "@babel/plugin-transform-member-expression-literals" "^7.24.7" 854 | "@babel/plugin-transform-modules-amd" "^7.24.7" 855 | "@babel/plugin-transform-modules-commonjs" "^7.24.8" 856 | "@babel/plugin-transform-modules-systemjs" "^7.25.0" 857 | "@babel/plugin-transform-modules-umd" "^7.24.7" 858 | "@babel/plugin-transform-named-capturing-groups-regex" "^7.24.7" 859 | "@babel/plugin-transform-new-target" "^7.24.7" 860 | "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.7" 861 | "@babel/plugin-transform-numeric-separator" "^7.24.7" 862 | "@babel/plugin-transform-object-rest-spread" "^7.24.7" 863 | "@babel/plugin-transform-object-super" "^7.24.7" 864 | "@babel/plugin-transform-optional-catch-binding" "^7.24.7" 865 | "@babel/plugin-transform-optional-chaining" "^7.24.8" 866 | "@babel/plugin-transform-parameters" "^7.24.7" 867 | "@babel/plugin-transform-private-methods" "^7.24.7" 868 | "@babel/plugin-transform-private-property-in-object" "^7.24.7" 869 | "@babel/plugin-transform-property-literals" "^7.24.7" 870 | "@babel/plugin-transform-regenerator" "^7.24.7" 871 | "@babel/plugin-transform-reserved-words" "^7.24.7" 872 | "@babel/plugin-transform-shorthand-properties" "^7.24.7" 873 | "@babel/plugin-transform-spread" "^7.24.7" 874 | "@babel/plugin-transform-sticky-regex" "^7.24.7" 875 | "@babel/plugin-transform-template-literals" "^7.24.7" 876 | "@babel/plugin-transform-typeof-symbol" "^7.24.8" 877 | "@babel/plugin-transform-unicode-escapes" "^7.24.7" 878 | "@babel/plugin-transform-unicode-property-regex" "^7.24.7" 879 | "@babel/plugin-transform-unicode-regex" "^7.24.7" 880 | "@babel/plugin-transform-unicode-sets-regex" "^7.24.7" 881 | "@babel/preset-modules" "0.1.6-no-external-plugins" 882 | babel-plugin-polyfill-corejs2 "^0.4.10" 883 | babel-plugin-polyfill-corejs3 "^0.10.4" 884 | babel-plugin-polyfill-regenerator "^0.6.1" 885 | core-js-compat "^3.37.1" 886 | semver "^6.3.1" 887 | 888 | "@babel/preset-modules@0.1.6-no-external-plugins": 889 | version "0.1.6-no-external-plugins" 890 | resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" 891 | integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== 892 | dependencies: 893 | "@babel/helper-plugin-utils" "^7.0.0" 894 | "@babel/types" "^7.4.4" 895 | esutils "^2.0.2" 896 | 897 | "@babel/regjsgen@^0.8.0": 898 | version "0.8.0" 899 | resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" 900 | integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== 901 | 902 | "@babel/runtime@^7.8.4": 903 | version "7.25.0" 904 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" 905 | integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== 906 | dependencies: 907 | regenerator-runtime "^0.14.0" 908 | 909 | "@babel/template@^7.24.7", "@babel/template@^7.25.0": 910 | version "7.25.0" 911 | resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" 912 | integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== 913 | dependencies: 914 | "@babel/code-frame" "^7.24.7" 915 | "@babel/parser" "^7.25.0" 916 | "@babel/types" "^7.25.0" 917 | 918 | "@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1": 919 | version "7.25.1" 920 | resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.1.tgz#64dbc31effc5f3fa3cf10d19df0e6310214743f5" 921 | integrity sha512-LrHHoWq08ZpmmFqBAzN+hUdWwy5zt7FGa/hVwMcOqW6OVtwqaoD5utfuGYU87JYxdZgLUvktAsn37j/sYR9siA== 922 | dependencies: 923 | "@babel/code-frame" "^7.24.7" 924 | "@babel/generator" "^7.25.0" 925 | "@babel/parser" "^7.25.0" 926 | "@babel/template" "^7.25.0" 927 | "@babel/types" "^7.25.0" 928 | debug "^4.3.1" 929 | globals "^11.1.0" 930 | 931 | "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.24.9", "@babel/types@^7.25.0", "@babel/types@^7.4.4": 932 | version "7.25.0" 933 | resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.0.tgz#e6e3656c581f28da8452ed4f69e38008ec0ba41b" 934 | integrity sha512-LcnxQSsd9aXOIgmmSpvZ/1yo46ra2ESYyqLcryaBZOghxy5qqOBjvCWP5JfkI8yl9rlxRgdLTTMCQQRcN2hdCg== 935 | dependencies: 936 | "@babel/helper-string-parser" "^7.24.8" 937 | "@babel/helper-validator-identifier" "^7.24.7" 938 | to-fast-properties "^2.0.0" 939 | 940 | "@jridgewell/gen-mapping@^0.3.5": 941 | version "0.3.5" 942 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" 943 | integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== 944 | dependencies: 945 | "@jridgewell/set-array" "^1.2.1" 946 | "@jridgewell/sourcemap-codec" "^1.4.10" 947 | "@jridgewell/trace-mapping" "^0.3.24" 948 | 949 | "@jridgewell/resolve-uri@^3.1.0": 950 | version "3.1.2" 951 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" 952 | integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== 953 | 954 | "@jridgewell/set-array@^1.2.1": 955 | version "1.2.1" 956 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" 957 | integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== 958 | 959 | "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": 960 | version "1.5.0" 961 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" 962 | integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== 963 | 964 | "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": 965 | version "0.3.25" 966 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" 967 | integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== 968 | dependencies: 969 | "@jridgewell/resolve-uri" "^3.1.0" 970 | "@jridgewell/sourcemap-codec" "^1.4.14" 971 | 972 | ansi-colors@^1.0.1: 973 | version "1.1.0" 974 | resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" 975 | dependencies: 976 | ansi-wrap "^0.1.0" 977 | 978 | ansi-styles@^3.2.1: 979 | version "3.2.1" 980 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 981 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 982 | dependencies: 983 | color-convert "^1.9.0" 984 | 985 | ansi-wrap@^0.1.0: 986 | version "0.1.0" 987 | resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" 988 | integrity sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw== 989 | 990 | arr-diff@^4.0.0: 991 | version "4.0.0" 992 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" 993 | integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== 994 | 995 | arr-union@^3.1.0: 996 | version "3.1.0" 997 | resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" 998 | integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== 999 | 1000 | assign-symbols@^1.0.0: 1001 | version "1.0.0" 1002 | resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" 1003 | integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== 1004 | 1005 | babel-plugin-polyfill-corejs2@^0.4.10: 1006 | version "0.4.11" 1007 | resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" 1008 | integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== 1009 | dependencies: 1010 | "@babel/compat-data" "^7.22.6" 1011 | "@babel/helper-define-polyfill-provider" "^0.6.2" 1012 | semver "^6.3.1" 1013 | 1014 | babel-plugin-polyfill-corejs3@^0.10.4: 1015 | version "0.10.4" 1016 | resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz#789ac82405ad664c20476d0233b485281deb9c77" 1017 | integrity sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg== 1018 | dependencies: 1019 | "@babel/helper-define-polyfill-provider" "^0.6.1" 1020 | core-js-compat "^3.36.1" 1021 | 1022 | babel-plugin-polyfill-regenerator@^0.6.1: 1023 | version "0.6.2" 1024 | resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" 1025 | integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== 1026 | dependencies: 1027 | "@babel/helper-define-polyfill-provider" "^0.6.2" 1028 | 1029 | browserslist@^4.23.0, browserslist@^4.23.1: 1030 | version "4.23.2" 1031 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.2.tgz#244fe803641f1c19c28c48c4b6ec9736eb3d32ed" 1032 | integrity sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA== 1033 | dependencies: 1034 | caniuse-lite "^1.0.30001640" 1035 | electron-to-chromium "^1.4.820" 1036 | node-releases "^2.0.14" 1037 | update-browserslist-db "^1.1.0" 1038 | 1039 | caniuse-lite@^1.0.30001640: 1040 | version "1.0.30001643" 1041 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz#9c004caef315de9452ab970c3da71085f8241dbd" 1042 | integrity sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg== 1043 | 1044 | chalk@^2.4.2: 1045 | version "2.4.2" 1046 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 1047 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 1048 | dependencies: 1049 | ansi-styles "^3.2.1" 1050 | escape-string-regexp "^1.0.5" 1051 | supports-color "^5.3.0" 1052 | 1053 | color-convert@^1.9.0: 1054 | version "1.9.3" 1055 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 1056 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 1057 | dependencies: 1058 | color-name "1.1.3" 1059 | 1060 | color-name@1.1.3: 1061 | version "1.1.3" 1062 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 1063 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== 1064 | 1065 | convert-source-map@^2.0.0: 1066 | version "2.0.0" 1067 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" 1068 | integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== 1069 | 1070 | core-js-compat@^3.36.1, core-js-compat@^3.37.1: 1071 | version "3.37.1" 1072 | resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.1.tgz#c844310c7852f4bdf49b8d339730b97e17ff09ee" 1073 | integrity sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg== 1074 | dependencies: 1075 | browserslist "^4.23.0" 1076 | 1077 | core-util-is@~1.0.0: 1078 | version "1.0.3" 1079 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 1080 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 1081 | 1082 | debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: 1083 | version "4.3.6" 1084 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" 1085 | integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== 1086 | dependencies: 1087 | ms "2.1.2" 1088 | 1089 | electron-to-chromium@^1.4.820: 1090 | version "1.5.2" 1091 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.2.tgz#6126ad229ce45e781ec54ca40db0504787f23d19" 1092 | integrity sha512-kc4r3U3V3WLaaZqThjYz/Y6z8tJe+7K0bbjUVo3i+LWIypVdMx5nXCkwRe6SWbY6ILqLdc1rKcKmr3HoH7wjSQ== 1093 | 1094 | escalade@^3.1.2: 1095 | version "3.1.2" 1096 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" 1097 | integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== 1098 | 1099 | escape-string-regexp@^1.0.5: 1100 | version "1.0.5" 1101 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 1102 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== 1103 | 1104 | esutils@^2.0.2: 1105 | version "2.0.3" 1106 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 1107 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 1108 | 1109 | extend-shallow@^3.0.2: 1110 | version "3.0.2" 1111 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" 1112 | integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== 1113 | dependencies: 1114 | assign-symbols "^1.0.0" 1115 | is-extendable "^1.0.1" 1116 | 1117 | function-bind@^1.1.2: 1118 | version "1.1.2" 1119 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 1120 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 1121 | 1122 | gensync@^1.0.0-beta.2: 1123 | version "1.0.0-beta.2" 1124 | resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" 1125 | integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== 1126 | 1127 | globals@^11.1.0: 1128 | version "11.12.0" 1129 | resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" 1130 | integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== 1131 | 1132 | gulp-babel@^8.0.0: 1133 | version "8.0.0" 1134 | resolved "https://registry.yarnpkg.com/gulp-babel/-/gulp-babel-8.0.0.tgz#e0da96f4f2ec4a88dd3a3030f476e38ab2126d87" 1135 | integrity sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ== 1136 | dependencies: 1137 | plugin-error "^1.0.1" 1138 | replace-ext "^1.0.0" 1139 | through2 "^2.0.0" 1140 | vinyl-sourcemaps-apply "^0.2.0" 1141 | 1142 | has-flag@^3.0.0: 1143 | version "3.0.0" 1144 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 1145 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 1146 | 1147 | hasown@^2.0.2: 1148 | version "2.0.2" 1149 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" 1150 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== 1151 | dependencies: 1152 | function-bind "^1.1.2" 1153 | 1154 | inherits@~2.0.3: 1155 | version "2.0.4" 1156 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 1157 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 1158 | 1159 | is-core-module@^2.13.0: 1160 | version "2.15.0" 1161 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" 1162 | integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== 1163 | dependencies: 1164 | hasown "^2.0.2" 1165 | 1166 | is-extendable@^1.0.1: 1167 | version "1.0.1" 1168 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" 1169 | integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== 1170 | dependencies: 1171 | is-plain-object "^2.0.4" 1172 | 1173 | is-plain-object@^2.0.4: 1174 | version "2.0.4" 1175 | resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" 1176 | integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== 1177 | dependencies: 1178 | isobject "^3.0.1" 1179 | 1180 | isarray@~1.0.0: 1181 | version "1.0.0" 1182 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 1183 | integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== 1184 | 1185 | isobject@^3.0.1: 1186 | version "3.0.1" 1187 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" 1188 | integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== 1189 | 1190 | js-tokens@^4.0.0: 1191 | version "4.0.0" 1192 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 1193 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 1194 | 1195 | jsesc@^2.5.1: 1196 | version "2.5.2" 1197 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" 1198 | integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== 1199 | 1200 | jsesc@~0.5.0: 1201 | version "0.5.0" 1202 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" 1203 | integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== 1204 | 1205 | json5@^2.2.3: 1206 | version "2.2.3" 1207 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" 1208 | integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== 1209 | 1210 | lodash.debounce@^4.0.8: 1211 | version "4.0.8" 1212 | resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" 1213 | integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== 1214 | 1215 | lru-cache@^5.1.1: 1216 | version "5.1.1" 1217 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" 1218 | integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== 1219 | dependencies: 1220 | yallist "^3.0.2" 1221 | 1222 | ms@2.1.2: 1223 | version "2.1.2" 1224 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 1225 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1226 | 1227 | node-releases@^2.0.14: 1228 | version "2.0.18" 1229 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" 1230 | integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== 1231 | 1232 | path-parse@^1.0.7: 1233 | version "1.0.7" 1234 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 1235 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 1236 | 1237 | picocolors@^1.0.0, picocolors@^1.0.1: 1238 | version "1.0.1" 1239 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" 1240 | integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== 1241 | 1242 | plugin-error@^1.0.1: 1243 | version "1.0.1" 1244 | resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c" 1245 | integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA== 1246 | dependencies: 1247 | ansi-colors "^1.0.1" 1248 | arr-diff "^4.0.0" 1249 | arr-union "^3.1.0" 1250 | extend-shallow "^3.0.2" 1251 | 1252 | process-nextick-args@~2.0.0: 1253 | version "2.0.1" 1254 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 1255 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 1256 | 1257 | readable-stream@~2.3.6: 1258 | version "2.3.8" 1259 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" 1260 | integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== 1261 | dependencies: 1262 | core-util-is "~1.0.0" 1263 | inherits "~2.0.3" 1264 | isarray "~1.0.0" 1265 | process-nextick-args "~2.0.0" 1266 | safe-buffer "~5.1.1" 1267 | string_decoder "~1.1.1" 1268 | util-deprecate "~1.0.1" 1269 | 1270 | regenerate-unicode-properties@^10.1.0: 1271 | version "10.1.1" 1272 | resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz#6b0e05489d9076b04c436f318d9b067bba459480" 1273 | integrity sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q== 1274 | dependencies: 1275 | regenerate "^1.4.2" 1276 | 1277 | regenerate@^1.4.2: 1278 | version "1.4.2" 1279 | resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" 1280 | integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== 1281 | 1282 | regenerator-runtime@^0.14.0: 1283 | version "0.14.1" 1284 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" 1285 | integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== 1286 | 1287 | regenerator-transform@^0.15.2: 1288 | version "0.15.2" 1289 | resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" 1290 | integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== 1291 | dependencies: 1292 | "@babel/runtime" "^7.8.4" 1293 | 1294 | regexpu-core@^5.3.1: 1295 | version "5.3.2" 1296 | resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" 1297 | integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== 1298 | dependencies: 1299 | "@babel/regjsgen" "^0.8.0" 1300 | regenerate "^1.4.2" 1301 | regenerate-unicode-properties "^10.1.0" 1302 | regjsparser "^0.9.1" 1303 | unicode-match-property-ecmascript "^2.0.0" 1304 | unicode-match-property-value-ecmascript "^2.1.0" 1305 | 1306 | regjsparser@^0.9.1: 1307 | version "0.9.1" 1308 | resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" 1309 | integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== 1310 | dependencies: 1311 | jsesc "~0.5.0" 1312 | 1313 | replace-ext@^1.0.0: 1314 | version "1.0.1" 1315 | resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" 1316 | integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== 1317 | 1318 | resolve@^1.14.2: 1319 | version "1.22.8" 1320 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" 1321 | integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== 1322 | dependencies: 1323 | is-core-module "^2.13.0" 1324 | path-parse "^1.0.7" 1325 | supports-preserve-symlinks-flag "^1.0.0" 1326 | 1327 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1328 | version "5.1.2" 1329 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1330 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1331 | 1332 | semver@^6.3.1: 1333 | version "6.3.1" 1334 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" 1335 | integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== 1336 | 1337 | source-map@^0.5.1: 1338 | version "0.5.7" 1339 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 1340 | integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== 1341 | 1342 | string_decoder@~1.1.1: 1343 | version "1.1.1" 1344 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1345 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1346 | dependencies: 1347 | safe-buffer "~5.1.0" 1348 | 1349 | supports-color@^5.3.0: 1350 | version "5.5.0" 1351 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1352 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1353 | dependencies: 1354 | has-flag "^3.0.0" 1355 | 1356 | supports-preserve-symlinks-flag@^1.0.0: 1357 | version "1.0.0" 1358 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 1359 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 1360 | 1361 | through2@^2.0.0: 1362 | version "2.0.5" 1363 | resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" 1364 | integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== 1365 | dependencies: 1366 | readable-stream "~2.3.6" 1367 | xtend "~4.0.1" 1368 | 1369 | to-fast-properties@^2.0.0: 1370 | version "2.0.0" 1371 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 1372 | integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== 1373 | 1374 | unicode-canonical-property-names-ecmascript@^2.0.0: 1375 | version "2.0.0" 1376 | resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" 1377 | integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== 1378 | 1379 | unicode-match-property-ecmascript@^2.0.0: 1380 | version "2.0.0" 1381 | resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" 1382 | integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== 1383 | dependencies: 1384 | unicode-canonical-property-names-ecmascript "^2.0.0" 1385 | unicode-property-aliases-ecmascript "^2.0.0" 1386 | 1387 | unicode-match-property-value-ecmascript@^2.1.0: 1388 | version "2.1.0" 1389 | resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" 1390 | integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== 1391 | 1392 | unicode-property-aliases-ecmascript@^2.0.0: 1393 | version "2.1.0" 1394 | resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" 1395 | integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== 1396 | 1397 | update-browserslist-db@^1.1.0: 1398 | version "1.1.0" 1399 | resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" 1400 | integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== 1401 | dependencies: 1402 | escalade "^3.1.2" 1403 | picocolors "^1.0.1" 1404 | 1405 | util-deprecate@~1.0.1: 1406 | version "1.0.2" 1407 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1408 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 1409 | 1410 | vinyl-sourcemaps-apply@^0.2.0: 1411 | version "0.2.1" 1412 | resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" 1413 | integrity sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw== 1414 | dependencies: 1415 | source-map "^0.5.1" 1416 | 1417 | xtend@~4.0.1: 1418 | version "4.0.2" 1419 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 1420 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 1421 | 1422 | yallist@^3.0.2: 1423 | version "3.1.1" 1424 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" 1425 | integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== 1426 | --------------------------------------------------------------------------------