├── .editorconfig ├── .github └── FUNDING.yml ├── .gitignore ├── .tool-versions ├── LICENSE ├── Makefile ├── README.md ├── package.json ├── src ├── app.ts ├── icons │ ├── about.txt │ ├── favicon-16.png │ ├── favicon-180.png │ ├── favicon-192.png │ ├── favicon-32.png │ ├── favicon-512.png │ └── favicon.ico ├── index.html ├── manifest.json ├── scripts │ ├── ClockPageView.ts │ └── migrate.ts ├── styles.css └── sw.js ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://EditorConfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = tab 8 | indent_size = 4 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.yml] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [sharat87] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ["https://www.buymeacoffee.com/sharat87"] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | .parcel-cache 4 | /yarn-error.log 5 | /*.pem 6 | /tmp-chrome-profile 7 | 8 | /.idea 9 | *.iml 10 | 11 | .DS_Store 12 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 18.16.0 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Shrikant Sharat Kandula 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | serve: 2 | @if [[ package.json -nt yarn.lock ]]; then yarn install; fi 3 | @if command -v mkcert &> /dev/null; then \ 4 | echo Starting server with HTTPS.; \ 5 | mkcert -install; \ 6 | mkcert localhost; \ 7 | npx parcel serve --port $${PORT-3020} --cert localhost.pem --key localhost-key.pem; \ 8 | else \ 9 | echo Starting server with HTTP.; \ 10 | npx parcel serve --port $${PORT-3020}; \ 11 | fi 12 | 13 | build: 14 | yarn install --frozen-lockfile 15 | npx parcel build --no-autoinstall --no-source-maps --no-cache --detailed-report 9 16 | 17 | chrome-with-tz: 18 | rm -rf tmp-chrome-profile 19 | TZ="$${TZ:-America/New_York}" open -na "Google Chrome" --args "--user-data-dir=$$PWD/tmp-chrome-profile" 20 | 21 | outdated: 22 | yarn outdated 23 | 24 | 25 | .PHONY: serve build chrome-with-tz outdated 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Just a Calendar. 2 | 3 | This is a small app that'll generate and show a simple Calendar in the browser. Why? 4 | 5 | 1. When I want to look at a Calendar, there's not a small light app that just shows me a Calendar, without a 100-odd *engagement* features. 6 | 1. When sharing screen, or planning dates with my wife, I want to be able to just put a mark on a date or two, without having to login and stuff. 7 | 8 | Icon by [favicon.io](https://favicon.io). 9 | 10 | [Discussion on HackerNews](https://news.ycombinator.com/item?id=30851174). 11 | 12 | ## Features 13 | 14 | 1. Simple, light, mostly greyscale. 15 | 1. No signup/login. Yes, this is considered a feature. 16 | 1. Go to any given date, and view it's Calendar. 17 | 1. Mark dates, click to toggle, drag to mark/unmark multiple. 18 | 1. Drag from one date to another, to get an estimate of the period between the dates. Hit Escape or right-click to cancel. 19 | 1. Generate and copy URL with marked dates for sharing. 20 | 1. Right click on any date to easily copy it in several formats. 21 | 1. Optional week numbers. 22 | 1. Weeks start on Monday or Sunday, configurable. 23 | 1. View consecutive Calendars together. 24 | 1. Works completely offline, and has PWA support. 25 | 1. Print beautiful no-nonsense Calendars, with customizable layouts. 26 | 27 | ## Roadmap 28 | 29 | Not much. I consider this almost a _finished_ software, and don't currently intend to add large and complicated features. But if it's small QoL improvements, or bugs, or even new related tools, they will be taken up when I find some bandwidth. 30 | 31 | So, if you have any suggestions or bugs you faced, please [let me know](https://github.com/sharat87/just-a-calendar/issues/new/choose). Thanks! 32 | 33 | ## License 34 | 35 | [MIT License](https://github.com/sharat87/just-a-calendar/blob/master/LICENSE). 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "just-a-calendar", 3 | "version": "1.0.0", 4 | "description": "Just a calendar web app", 5 | "repository": "https://github.com/sharat87/just-a-calendar", 6 | "author": "Shrikant Sharat Kandula ", 7 | "license": "MIT", 8 | "private": false, 9 | "source": "src/index.html", 10 | "browserslist": [ 11 | "since 2017-06" 12 | ], 13 | "@parcel/transformer-css": { 14 | "drafts": { 15 | "nesting": true, 16 | "customMedia": true 17 | } 18 | }, 19 | "devDependencies": { 20 | "@parcel/packager-raw-url": "2.9.1", 21 | "@parcel/service-worker": "^2.9.1", 22 | "@parcel/transformer-webmanifest": "2.9.1", 23 | "@types/mithril": "^2.0.12", 24 | "mithril": "^2.2.2", 25 | "parcel": "^2.9.1", 26 | "typescript": "^5.1.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import m from "mithril" 2 | import ClockPageView from "./scripts/ClockPageView" 3 | import * as migrate from "./scripts/migrate" 4 | 5 | const LANG = "en" 6 | 7 | const MONTHS: string[] = [] 8 | for (let i = 0, f = new Intl.DateTimeFormat(LANG, { month: "long" }).format; i < 12; ++i) { 9 | MONTHS.push(f(new Date(2000, i))) 10 | } 11 | 12 | const WEEKDAYS: string[] = [] 13 | for (let i = 0, f = new Intl.DateTimeFormat(LANG, { weekday: "long" }).format; i < 7; ++i) { 14 | WEEKDAYS.push(f(new Date(2000, 0, i + 2))) 15 | } 16 | 17 | const MARK_COLORS = ["coral", "deeppink", "green", "purple"] 18 | 19 | window.addEventListener("load", main) 20 | 21 | function main() { 22 | if (migrate.needsMigrate()) { 23 | return 24 | } 25 | 26 | m.route.prefix = "" 27 | m.route(document.body, "/", { 28 | "/": { 29 | render() { 30 | return m(".page-calendar", m(CalendarPageView)) 31 | }, 32 | }, 33 | "/clock": { 34 | render() { 35 | return m(".page-clock", m(ClockPageView)) 36 | }, 37 | }, 38 | }) 39 | 40 | // Register a service-worker to support PWA installations. 41 | if (navigator.serviceWorker) { 42 | navigator.serviceWorker.register( 43 | new URL("./sw.js", import.meta.url), 44 | { type: "module" }, 45 | ).catch(err => { 46 | console.error("Error registering service worker", err) 47 | }) 48 | } 49 | 50 | // Online/offline detection. 51 | window.addEventListener("online", m.redraw) 52 | window.addEventListener("offline", m.redraw) 53 | } 54 | 55 | class Model { 56 | currentYear: number 57 | markedDates: Record 58 | markStorage: "localStorage" | "queryParams" 59 | dragState: null | DragBaseState 60 | additionalCalendarCount: number 61 | contextMenu: null | { date: Date, top: number, left: number } 62 | isHelpVisible: boolean 63 | visibleDialog: null | "options" 64 | printLayout: "1" | "2" | "3" | "4" | "6" | "12" // Page count, months divided equally. 65 | colorChangedByHotkeyAt: number 66 | 67 | constructor() { 68 | // Ensure every field has a default value, before _any_ method is called. 69 | this.currentYear = 0 70 | this.markedDates = {} 71 | this.markStorage = "localStorage" 72 | this.dragState = null 73 | this.additionalCalendarCount = 0 74 | this.contextMenu = null 75 | this.isHelpVisible = false 76 | this.visibleDialog = null 77 | this.printLayout = "2" 78 | this.colorChangedByHotkeyAt = 0 79 | 80 | const now = new Date() 81 | this.goToYear(now.getFullYear()) 82 | 83 | const url = new URL(location.toString()) 84 | const urlDs = url.searchParams.get("d") 85 | if (urlDs != null) { 86 | this.markStorage = "queryParams" 87 | } 88 | this.loadMarks() 89 | } 90 | 91 | goToYear(target: number | string) { 92 | const prevCurrentYear = this.currentYear 93 | 94 | if (typeof target === "string") { 95 | this.currentYear += parseInt(target, 10) 96 | } else { 97 | this.currentYear = target 98 | } 99 | 100 | if (this.currentYear !== prevCurrentYear) { 101 | // When current year has changed, clear the additional calendars. 102 | this.additionalCalendarCount = 0 103 | } 104 | } 105 | 106 | promptGoToDate() { 107 | const dateStr = prompt("Enter date (Any clearly understood format is okay):") 108 | if (dateStr) { 109 | const date = parseDate(dateStr) 110 | if (date) { 111 | this.goToDate(date) 112 | m.redraw() // I think this is needed because of the `prompt` call. 113 | } 114 | } 115 | } 116 | 117 | goToDate(date: Date): void { 118 | this.currentYear = date.getFullYear() 119 | setTimeout(() => flash(`[data-date="${dateToBasicIso(date)}"]:not(.diff-month)`), 100) 120 | } 121 | 122 | get ghostDatesEnabled(): boolean { 123 | return localStorage.getItem("ghostMode") === "1" 124 | } 125 | 126 | set ghostDatesEnabled(value: boolean) { 127 | localStorage.setItem("ghostMode", value ? "1" : "0") 128 | } 129 | 130 | get weekStartsOn(): "Monday" | "Sunday" { 131 | const value = localStorage.getItem("weekStartsOn") 132 | if (value === "Monday" || value === "Sunday") { 133 | return value 134 | } 135 | return "Monday" 136 | } 137 | 138 | set weekStartsOn(value: "Monday" | "Sunday") { 139 | localStorage.setItem("weekStartsOn", value) 140 | } 141 | 142 | get currentColor(): string { 143 | return localStorage.getItem("currentColor") ?? MARK_COLORS[0] 144 | } 145 | 146 | set currentColor(value: string) { 147 | localStorage.setItem("currentColor", value) 148 | } 149 | 150 | get weekNumbersEnabled(): boolean { 151 | return localStorage.getItem("weekNumbersEnabled") === "1" 152 | } 153 | 154 | set weekNumbersEnabled(value: boolean) { 155 | localStorage.setItem("weekNumbersEnabled", value ? "1" : "0") 156 | } 157 | 158 | toggleMark(dateStr: string) { 159 | if (this.markedDates[dateStr]) { 160 | this.unsetMark(dateStr) 161 | } else { 162 | this.setMark(dateStr) 163 | } 164 | } 165 | 166 | unsetMark(dateStr: string) { 167 | delete this.markedDates[dateStr] 168 | this.saveMarks() 169 | } 170 | 171 | setMark(dateStr: string) { 172 | this.markedDates[dateStr] = this.currentColor 173 | this.saveMarks() 174 | } 175 | 176 | clearMarks() { 177 | this.markedDates = {} 178 | this.saveMarks() 179 | } 180 | 181 | loadMarks() { 182 | this.markedDates = {} 183 | 184 | if (this.markStorage === "localStorage") { 185 | this.markedDates = this.loadLocalStorageMarks() 186 | 187 | } else if (this.markStorage === "queryParams") { 188 | const urlDs = new URL(location.toString()).searchParams.get("d") 189 | if (urlDs == null) { 190 | console.error("Attempt to load marks from query params, when not available.") 191 | // Switch to `localStorage` here? 192 | return 193 | } 194 | 195 | // Example: ?d=ccoral,20220110,20221223,cdeeppink,20200101 196 | const parts: string[] = urlDs.split(",") 197 | 198 | let currentColor = MARK_COLORS[0] 199 | 200 | for (const part of parts) { 201 | const instruction = part.charAt(0) 202 | if (instruction === "c") { 203 | currentColor = part.substring(1) 204 | } else if (part.match(/^\d{8}$/)) { 205 | this.markedDates[part] = currentColor 206 | } else { 207 | console.error(`Couldn't parse date '${part}'. Should be in the format 'YYYYMMDD' only.`) 208 | } 209 | } 210 | 211 | } 212 | } 213 | 214 | saveMarks() { 215 | if (this.markStorage === "localStorage") { 216 | localStorage.setItem("marksV2", JSON.stringify(Object.entries(this.markedDates))) 217 | 218 | } else if (this.markStorage === "queryParams") { 219 | history.replaceState(null, "", this.generateLinkWithMarks()) 220 | 221 | } 222 | } 223 | 224 | getLocalStorageMarkCount(): number { 225 | return Object.keys(this.loadLocalStorageMarks()).length 226 | } 227 | 228 | loadLocalStorageMarks(): Record { 229 | const markedDates: Record = {} 230 | 231 | const body = localStorage.getItem("marksV2") 232 | if (body == null) { 233 | return {} 234 | } 235 | 236 | const data = JSON.parse(body) 237 | for (const [date, color] of data) { 238 | markedDates[date.replace(/\D/g, "")] = color 239 | } 240 | 241 | return markedDates 242 | } 243 | 244 | generateLinkWithMarks(): string { 245 | const datesByColor: Record = {} 246 | for (const [dateStr, markColor] of Object.entries(this.markedDates)) { 247 | (datesByColor[markColor] ?? (datesByColor[markColor] = [])).push(dateStr) 248 | } 249 | 250 | const colors: string[] = Object.keys(datesByColor) 251 | colors.sort() 252 | 253 | const parts: string[] = [] 254 | for (const color of colors) { 255 | parts.push("c" + color) 256 | for (const dateStr of datesByColor[color].sort()) { 257 | parts.push(dateStr) 258 | } 259 | } 260 | 261 | const url = new URL(location.toString()) 262 | url.search = "?d=" + parts.join(",") 263 | return url.toString() 264 | 265 | } 266 | 267 | exportMarksToText() { 268 | const lines: string[] = [] 269 | 270 | for (const dateStr of Object.keys(this.markedDates)) { 271 | lines.push(dateStr.replace(/^(\d\d\d\d)(\d\d)(\d\d)$/, "$1-$2-$3")) 272 | } 273 | 274 | return lines.join("\n") 275 | } 276 | 277 | prepareAndPrint() { 278 | const styleEl = document.createElement("style") 279 | document.body.appendChild(styleEl) 280 | setTimeout(styleEl.remove.bind(styleEl), 1000) 281 | setTimeout(window.print, 10) 282 | } 283 | } 284 | 285 | abstract class DragBaseState { 286 | isUnmarking: boolean 287 | pos: { 288 | x: number 289 | y: number 290 | } 291 | 292 | protected constructor() { 293 | this.isUnmarking = false 294 | this.pos = { x: 0, y: 0 } 295 | } 296 | 297 | abstract computeDateSet(): Set 298 | } 299 | 300 | class DragDateState extends DragBaseState { 301 | start: Date 302 | end: Date 303 | 304 | constructor(start: Date, end: Date) { 305 | super() 306 | this.start = start 307 | this.end = end 308 | } 309 | 310 | computeDateSet(): Set { 311 | if (this.start == null || this.end == null) { 312 | return new Set() 313 | } 314 | 315 | const [lowerDate, higherDate] = normalizedValueOf(this.start) < normalizedValueOf(this.end) 316 | ? [this.start, this.end] : [this.end, this.start] 317 | 318 | return computeDateSet(lowerDate, higherDate) 319 | } 320 | } 321 | 322 | class DragWeekState extends DragBaseState { 323 | start: Date 324 | end: Date 325 | endType: "date" | "week" 326 | 327 | constructor(start: Date, end: Date) { 328 | super() 329 | this.start = start 330 | this.end = end 331 | this.endType = "week" 332 | } 333 | 334 | computeDateSet(): Set { 335 | if (this.start == null || this.end == null) { 336 | return new Set() 337 | } 338 | 339 | let lowerDate: Date 340 | let higherDate: Date 341 | 342 | if (normalizedValueOf(this.start) < normalizedValueOf(this.end)) { 343 | lowerDate = this.start 344 | higherDate = this.endType === "week" ? dateAddDays(this.end, 6): this.end 345 | } else { 346 | lowerDate = this.end 347 | higherDate = dateAddDays(this.start, 6) 348 | } 349 | 350 | return computeDateSet(lowerDate, higherDate) 351 | } 352 | } 353 | 354 | function computeDateSet(lowerDate: Date, higherDate: Date) { 355 | const d = new Date(lowerDate) 356 | 357 | const dateSet: Set = new Set() 358 | while (!isSameDate(d, higherDate)) { 359 | dateSet.add(dateToBasicIso(d)) 360 | d.setDate(d.getDate() + 1) 361 | } 362 | 363 | dateSet.add(dateToBasicIso(higherDate)) 364 | return dateSet 365 | } 366 | 367 | class CalendarPageView implements m.ClassComponent { 368 | model: Model 369 | touchStartedAt: null | { 370 | time: number 371 | scrollX: number 372 | scrollY: number 373 | } 374 | 375 | constructor() { 376 | this.model = new Model() 377 | this.touchStartedAt = null 378 | this.onMouseDown = this.onMouseDown.bind(this) 379 | this.onMouseMove = this.onMouseMove.bind(this) 380 | this.onMouseUp = this.onMouseUp.bind(this) 381 | this.onContextMenu = this.onContextMenu.bind(this) 382 | this.hotkeyHandler = this.hotkeyHandler.bind(this) 383 | } 384 | 385 | oncreate(): void { 386 | document.body.addEventListener("keydown", this.hotkeyHandler) 387 | } 388 | 389 | onremove(): void { 390 | document.body.removeEventListener("keydown", this.hotkeyHandler) 391 | } 392 | 393 | view(): m.Children { 394 | return m( 395 | "div", 396 | { 397 | class: this.model.ghostDatesEnabled ? "ghosts" : undefined, 398 | onmousedown: this.onMouseDown, 399 | ...(this.model.dragState == null ? {} : { onmousemove: this.onMouseMove, onmouseup: this.onMouseUp }), 400 | oncontextmenu: this.onContextMenu, 401 | ontouchstart: (event: TouchEvent) => { 402 | if ((event.target as HTMLElement).dataset.date != null) { 403 | this.touchStartedAt = { 404 | time: Date.now(), 405 | scrollX: window.scrollX, 406 | scrollY: window.scrollY, 407 | } 408 | } 409 | }, 410 | ontouchend: (event: TouchEvent) => { 411 | const dateStr = (event.target as HTMLElement).dataset.date 412 | if (dateStr != null 413 | && this.touchStartedAt != null 414 | && Date.now() - this.touchStartedAt.time < 200 415 | && Math.abs(window.scrollX - this.touchStartedAt.scrollX) < 3 416 | && Math.abs(window.scrollY - this.touchStartedAt.scrollY) < 3 417 | ) { 418 | this.model.toggleMark(dateStr) 419 | } 420 | }, 421 | }, 422 | [ 423 | m(TitleView), 424 | m(TopToolbarView, { model: this.model }), 425 | m(CalendarView, { 426 | year: this.model.currentYear, 427 | model: this.model, 428 | }), 429 | m(AdditionalCalendarsView, { 430 | model: this.model, 431 | }), 432 | m(FooterView), 433 | m(ContextMenuView, { model: this.model }), 434 | this.model.dragState != null && m(DragDatePeriodView, { dragState: this.model.dragState }), 435 | this.model.visibleDialog === "options" && m(OptionsDialogView, { model: this.model }), 436 | this.model.isHelpVisible && m(HelpDialogView), 437 | m(StorageInfoView, { model: this.model }), 438 | Date.now() - this.model.colorChangedByHotkeyAt < 3000 && 439 | m(ColorChangeOSDView, { model: this.model }), 440 | ], 441 | ) 442 | } 443 | 444 | private onMouseDown(event: MouseEvent) { 445 | if (event.buttons !== 1) { 446 | return 447 | } 448 | 449 | const el = event.target as HTMLElement 450 | let d 451 | 452 | if (el.dataset.date && (d = parseDate(el.dataset.date)) != null) { 453 | this.model.dragState = new DragDateState(d, d) 454 | this.model.dragState.isUnmarking = this.model.markedDates[dateToBasicIso(d)] === this.model.currentColor 455 | this.model.dragState.pos = { 456 | x: event.clientX, 457 | y: event.clientY, 458 | } 459 | event.preventDefault() 460 | } 461 | 462 | if (el.dataset.weekStart && (d = parseDate(el.dataset.weekStart)) != null) { 463 | this.model.dragState = new DragWeekState(d, d) 464 | this.model.dragState.isUnmarking = this.model.markedDates[dateToBasicIso(d)] === this.model.currentColor 465 | this.model.dragState.pos = { 466 | x: event.clientX, 467 | y: event.clientY, 468 | } 469 | event.preventDefault() 470 | } 471 | } 472 | 473 | private onMouseMove(event: MouseEvent) { 474 | if (this.model.dragState == null) { 475 | return 476 | } 477 | 478 | const el = event.target as HTMLElement 479 | if (this.model.dragState instanceof DragDateState) { 480 | if (el.dataset.date != null) { 481 | const d = parseDate(el.dataset.date) 482 | if (d != null) { 483 | this.model.dragState.end = d 484 | } 485 | } 486 | 487 | } else if (this.model.dragState instanceof DragWeekState) { 488 | if (el.dataset.weekStart != null) { 489 | const d = parseDate(el.dataset.weekStart) 490 | if (d != null) { 491 | this.model.dragState.end = d 492 | } 493 | this.model.dragState.endType = "week" 494 | } else if (el.dataset.date != null) { 495 | const d = parseDate(el.dataset.date) 496 | if (d != null) { 497 | this.model.dragState.end = d 498 | } 499 | this.model.dragState.endType = "date" 500 | } 501 | 502 | } 503 | 504 | this.model.dragState.pos = { 505 | x: event.clientX, 506 | y: event.clientY, 507 | } 508 | } 509 | 510 | private onMouseUp(event: MouseEvent) { 511 | if (this.model.dragState == null) { 512 | return 513 | } 514 | for (const d of this.model.dragState.computeDateSet()) { 515 | if (this.model.dragState.isUnmarking) { 516 | this.model.unsetMark(d) 517 | } else { 518 | this.model.setMark(d) 519 | } 520 | } 521 | this.model.dragState = null 522 | event.preventDefault() 523 | } 524 | 525 | private onContextMenu(event: MouseEvent) { 526 | if (this.model.dragState != null) { 527 | // If a drag is in-progress, cancel it. 528 | this.model.dragState = null 529 | event.preventDefault() 530 | return 531 | } 532 | const el = event.target as HTMLElement 533 | if (el.dataset.date == null || event.shiftKey) { 534 | return 535 | } 536 | event.preventDefault() 537 | const d = parseDate(el.dataset.date) 538 | if (d == null) { 539 | return 540 | } 541 | 542 | if (isSameDate(this.model.contextMenu?.date ?? null, d)) { 543 | this.model.contextMenu = null 544 | } else { 545 | const tdRect = el.getBoundingClientRect() 546 | this.model.contextMenu = { 547 | date: d, 548 | top: tdRect.bottom + window.scrollY, 549 | left: tdRect.left + window.scrollX, 550 | } 551 | } 552 | } 553 | 554 | private hotkeyHandler(event: KeyboardEvent) { 555 | if ((event.target as HTMLElement).matches("input:not([type='checkbox']), textarea") && event.key !== "Escape") { 556 | return 557 | } 558 | 559 | if ((event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey && event.key === "p") { 560 | // Print hotkey. 561 | event.preventDefault() 562 | this.model.prepareAndPrint() 563 | return 564 | } 565 | 566 | if (event.ctrlKey || event.metaKey || event.altKey) { 567 | return 568 | } 569 | 570 | switch(event.key) { 571 | case "?": 572 | this.model.isHelpVisible = !this.model.isHelpVisible 573 | break 574 | case "t": 575 | this.model.goToDate(new Date()) 576 | break 577 | case "g": 578 | this.model.promptGoToDate() 579 | break 580 | case "n": 581 | this.model.goToYear("+1") 582 | break 583 | case "p": 584 | this.model.goToYear("-1") 585 | break 586 | case "N": 587 | this.model.goToYear("+5") 588 | break 589 | case "P": 590 | this.model.goToYear("-5") 591 | break 592 | case "1": 593 | case "2": 594 | case "3": 595 | case "4": 596 | this.model.currentColor = MARK_COLORS[parseInt(event.key, 10) - 1] 597 | this.model.colorChangedByHotkeyAt = Date.now() 598 | setTimeout(m.redraw, 3000) 599 | break 600 | case "Escape": 601 | this.model.isHelpVisible = false 602 | this.model.visibleDialog = this.model.contextMenu = this.model.dragState = null 603 | break 604 | } 605 | 606 | m.redraw() 607 | } 608 | 609 | } 610 | 611 | class TitleView implements m.ClassComponent { 612 | view(_: m.Vnode): m.Children { 613 | return [ 614 | m("h1.screen", "Just a Calendar."), 615 | m("p.center.screen", ["🎉 ", m.trust(dateToHumanReadable(new Date())), "."]), 616 | ] 617 | } 618 | } 619 | 620 | class TopToolbarView implements m.ClassComponent<{ model: Model }> { 621 | view(vnode: m.Vnode<{ model: Model }>) { 622 | const model = vnode.attrs.model 623 | return m("p.controls.screen", [ 624 | m("button", { 625 | onclick() { 626 | model.goToYear("-5") 627 | }, 628 | }, m.trust("−5")), 629 | m("button", { 630 | onclick() { 631 | model.goToYear("-1") 632 | }, 633 | }, m.trust("−1")), 634 | m("input.year-input", { 635 | type: "number", 636 | value: model.currentYear, 637 | onchange(event: InputEvent) { 638 | model.currentYear = (event.target as HTMLInputElement).valueAsNumber 639 | }, 640 | }), 641 | m("button", { 642 | onclick() { 643 | model.goToYear("+1") 644 | }, 645 | }, "+1"), 646 | m("button", { 647 | onclick() { 648 | model.goToYear("+5") 649 | }, 650 | }, "+5"), 651 | m("button", { 652 | onclick() { 653 | model.goToDate(new Date()) 654 | }, 655 | }, [m("u", "T"), "oday"]), 656 | m("button", { 657 | onclick() { 658 | model.promptGoToDate() 659 | }, 660 | }, [m("u", "G"), "o to date"]), 661 | m("button", { 662 | title: "Options", 663 | style: { 664 | display: "flex", 665 | alignItems: "center", 666 | }, 667 | onclick() { 668 | model.visibleDialog = model.visibleDialog === "options" ? null : "options" 669 | }, 670 | }, m(BurgerIcon)), 671 | ]) 672 | } 673 | } 674 | 675 | class Icon implements m.ClassComponent { 676 | view(vnode: m.Vnode) { 677 | return m( 678 | "svg.i", 679 | { 680 | version: "1.1", 681 | width: "1em", 682 | height: "1em", 683 | viewBox: "0 0 10 10", 684 | xmlns: "http://www.w3.org/2000/svg", 685 | "stroke-linecap": "round", 686 | ...vnode.attrs, 687 | }, 688 | vnode.children, 689 | ) 690 | } 691 | } 692 | 693 | class BurgerIcon implements m.ClassComponent { 694 | view() { 695 | return m( 696 | Icon, 697 | { 698 | stroke: "currentColor", 699 | "stroke-width": 1, 700 | }, 701 | [ 702 | m("line", { x1: 1, y1: 2, x2: 9, y2: 2 }), 703 | m("line", { x1: 1, y1: 5, x2: 9, y2: 5 }), 704 | m("line", { x1: 1, y1: 8, x2: 9, y2: 8 }), 705 | ], 706 | ) 707 | } 708 | } 709 | 710 | class PrinterIcon implements m.ClassComponent { 711 | view() { 712 | return m( 713 | Icon, 714 | { 715 | stroke: "none", 716 | fill: "currentColor", 717 | }, 718 | [ 719 | m("rect", { x: 3, y: 2, width: 4, height: 2 }), 720 | m("polygon", { points: "1,4 3,4 3,6 7,6 7,4 9,4 9,8 1,8" }), 721 | ], 722 | ) 723 | } 724 | } 725 | 726 | class InfoIcon implements m.ClassComponent { 727 | view() { 728 | return m( 729 | Icon, 730 | { 731 | stroke: "currentColor", 732 | fill: "none", 733 | }, 734 | [ 735 | m("circle", { cx: 5, cy: 5, r: 4 }), 736 | m("line", { x1: 5, y1: 3, x2: 5, y2: 5 }), 737 | m("line", { x1: 5, y1: 6.5, x2: 5, y2: 7 }), 738 | ], 739 | ) 740 | } 741 | } 742 | 743 | class CalendarView implements m.ClassComponent<{ year: number, model: Model }> { 744 | view(vnode: m.Vnode<{ year: number, model: Model }>): m.Children { 745 | const { year, model } = vnode.attrs 746 | const children = [] 747 | 748 | const factor = 12 / parseInt(model.printLayout, 10) 749 | document.body.dataset.printLayout = model.printLayout 750 | 751 | for (let i = 0; i < 12; ++i) { 752 | if (i % factor === 0) { 753 | children.push( 754 | m("h1.print", m.trust(`Just a Calendar — by calendar.sharats.me`)), 755 | m("h2.print", [ 756 | factor === 1 ? MONTHS[i] : [MONTHS[i], m.trust(` – `), MONTHS[i + factor - 1]], 757 | m.trust(" — "), 758 | year, 759 | ]), 760 | ) 761 | } 762 | children.push(m(MonthTableView, { year, month: i, model })) 763 | } 764 | 765 | return [ 766 | m("h2.screen", ["Year ", year]), 767 | m(".calendar", children), 768 | ] 769 | } 770 | } 771 | 772 | class AdditionalCalendarsView implements m.ClassComponent<{ model: Model }> { 773 | view(vnode: m.Vnode<{ model: Model }>): m.Children { 774 | const { currentYear, additionalCalendarCount } = vnode.attrs.model 775 | const calendarViews = [] 776 | 777 | for (let i = 0; i < additionalCalendarCount; ++i) { 778 | calendarViews.push(m("hr"), m(CalendarView, { year: currentYear + i + 1, model: vnode.attrs.model })) 779 | } 780 | 781 | return [ 782 | calendarViews, 783 | m("p.controls.screen", m("button", { 784 | onclick() { 785 | ++vnode.attrs.model.additionalCalendarCount 786 | }, 787 | }, `Show ${currentYear + additionalCalendarCount + 1} Calendar here`)), 788 | ] 789 | } 790 | } 791 | 792 | // Renders a single month. 793 | class MonthTableView implements m.ClassComponent<{ year: number, model: Model, month: number }> { 794 | view(vnode: m.Vnode<{ year: number, model: Model, month: number }>) { 795 | const { markedDates, contextMenu } = vnode.attrs.model 796 | const { year, model, month } = vnode.attrs 797 | 798 | const weekdayNamesInOrder = [ 799 | ...WEEKDAYS.slice(WEEKDAYS.indexOf(model.weekStartsOn)), 800 | ...WEEKDAYS.slice(0, WEEKDAYS.indexOf(model.weekStartsOn)), 801 | ] 802 | 803 | const weekdayNumbersInOrder = weekdayNamesInOrder.map((name: string) => WEEKDAYS.indexOf(name)) 804 | 805 | const weekRows = [] 806 | const today = new Date() 807 | 808 | const date = new Date(year, month, 1) 809 | date.setDate(1 + weekdayNumbersInOrder[0] - (date.getDay() || 7)) // Go the most recent past start-of-week. 810 | const dragDates: Set = model.dragState == null ? new Set() : model.dragState.computeDateSet() 811 | 812 | for (let rowNum = 0; rowNum < 6; ++rowNum) { 813 | const row = [] 814 | if (model.weekNumbersEnabled) { 815 | const weekNum = computeWeekNumber(date) 816 | row.push(m( 817 | "th.week-num", 818 | { 819 | "data-week-start": dateToBasicIso(date), 820 | class: date.getMonth() === month ? undefined : "diff-month", 821 | }, 822 | weekNum, 823 | )) 824 | } 825 | for (let colNum = 0; colNum < 7; ++colNum) { 826 | const dateStr: string = dateToBasicIso(date) 827 | row.push(m("td.date", { 828 | "data-date": dateStr, 829 | class: [ 830 | date.getMonth() === month ? "" : "diff-month", 831 | isWeekend(date) ? "weekend" : "", 832 | isSameDate(date, today) ? "today" : "", 833 | (model.dragState instanceof DragDateState || model.dragState instanceof DragWeekState) 834 | && isSameDate(date, model.dragState.start) 835 | && dragDates.size > 1 836 | ? "drag-start" : "", 837 | dragDates.has(dateStr) 838 | ? (model.dragState?.isUnmarking ? "" : `mark mark-${model.currentColor}`) 839 | : (markedDates[dateStr] ? `mark mark-${markedDates[dateStr]}` : ""), 840 | isSameDate(date, contextMenu?.date ?? null) ? "has-cmenu" : "", 841 | ].join(" ").trim() || undefined, 842 | }, date.getDate())) 843 | date.setDate(date.getDate() + 1) 844 | } 845 | weekRows.push(m("tr", row)) 846 | } 847 | 848 | return m("table.month", [ 849 | m("thead", [ 850 | m("tr", m("th", { colspan: model.weekNumbersEnabled ? 8 : 7 }, `${MONTHS[month]} ${year}`)), 851 | m("tr", [ 852 | model.weekNumbersEnabled && m("th", m("code", "W#")), 853 | weekdayNamesInOrder.map((day) => m("th", m("code", day.slice(0, 2)))), 854 | ]), 855 | ]), 856 | m("tbody", weekRows), 857 | ]) 858 | } 859 | } 860 | 861 | class FooterView implements m.ClassComponent { 862 | view() { 863 | return m("footer.screen", [ 864 | m("p", [ 865 | "Hit ", 866 | m("kbd", "?"), 867 | " for help. ", 868 | !navigator.onLine && "Working offline. ", 869 | m("a", { href: "https://www.buymeacoffee.com/sharat87" }, "Support Just A Calendar ❤️"), 870 | ".", 871 | ]), 872 | m("p", [ 873 | m.trust("© 2018–2022 — "), 874 | m("a", { href: "https://sharats.me", target: "_blank" }, "Shri"), 875 | ". Source on ", 876 | m("a", { href: "https://github.com/sharat87/just-a-calendar", target: "_blank" }, "GitHub"), 877 | ".", 878 | ]), 879 | ]) 880 | } 881 | } 882 | 883 | class ContextMenuView implements m.ClassComponent<{ model: Model }> { 884 | view(vnode: m.Vnode<{ model: Model }>) { 885 | const { model } = vnode.attrs 886 | 887 | if (model.contextMenu == null) { 888 | return null 889 | } 890 | 891 | const date = model.contextMenu.date 892 | const dateStrings = [ 893 | formatDate(date, "%Y-%m-%d"), 894 | formatDate(date, "%m/%d/%Y"), 895 | formatDate(date, "%d-%M-%Y"), 896 | ] 897 | 898 | const localFormat = date.toLocaleDateString() 899 | if (!dateStrings.includes(localFormat)) { 900 | dateStrings.push(localFormat) 901 | } 902 | 903 | return m( 904 | ".cmenu.popup.show", 905 | { 906 | style: { 907 | top: model.contextMenu.top + "px", 908 | left: model.contextMenu.left + "px", 909 | }, 910 | }, 911 | m(MarkColorInput, { 912 | value: model.markedDates[dateToBasicIso(date)] ?? "", 913 | onNewValue(value: string) { 914 | if (value === "") { 915 | delete model.markedDates[dateToBasicIso(date)] 916 | } else { 917 | model.markedDates[dateToBasicIso(date)] = value 918 | } 919 | model.saveMarks() 920 | model.contextMenu = null 921 | }, 922 | includeClear: true, 923 | }), 924 | dateStrings.map((ds: string) => m("a", { 925 | href: "#", 926 | onclick(event: MouseEvent) { 927 | event.preventDefault() 928 | copyText(ds) 929 | .then(() => showOSD(`Copied "${ds}" to clipboard`)) 930 | model.contextMenu = null 931 | }, 932 | }, "Copy " + ds)), 933 | m("a", { 934 | href: "#", 935 | onclick(event: MouseEvent) { 936 | event.preventDefault() 937 | model.contextMenu = null 938 | } 939 | }, "Close") 940 | ) 941 | } 942 | } 943 | 944 | class DragDatePeriodView implements m.ClassComponent<{ dragState: DragBaseState }> { 945 | view(vnode: m.Vnode<{ dragState: DragBaseState }>): m.Children { 946 | const { dragState } = vnode.attrs 947 | 948 | const dayCount = dragState.computeDateSet().size 949 | if (dayCount < 2) { 950 | return null 951 | } 952 | 953 | const { weeks } = computeMessagesForDayCount(dayCount) 954 | 955 | const isBackwards = 956 | (dragState instanceof DragDateState || dragState instanceof DragWeekState) 957 | && dragState.start.valueOf() > dragState.end.valueOf() 958 | 959 | return m( 960 | "ul.drag-date-period", 961 | { 962 | class: isBackwards ? "up" : undefined, 963 | style: { 964 | top: dragState.pos.y + "px", 965 | left: dragState.pos.x + "px", 966 | }, 967 | }, 968 | [ 969 | m("li", [dayCount, " day", dayCount > 1 && "s"]), 970 | weeks != null && m("li", [weeks, " week", weeks !== "1" && "s"]), 971 | ], 972 | ) 973 | } 974 | } 975 | 976 | class HelpDialogView implements m.ClassComponent { 977 | view() { 978 | return m(".help-dialog.dialog", [ 979 | m("h1", "Hotkeys"), 980 | m("table", [ 981 | m("thead", m("tr", [ 982 | m("th", "Keys"), 983 | m("th", "Action"), 984 | ])), 985 | m("tbody", [ 986 | m("tr", [ 987 | m("td", m("code", "?")), 988 | m("td", "Toggle this help popup"), 989 | ]), 990 | m("tr", [ 991 | m("td", m("code", "g")), 992 | m("td", "Go to a given date"), 993 | ]), 994 | m("tr", [ 995 | m("td", m("code", "n")), 996 | m("td", "Go to the next year"), 997 | ]), 998 | m("tr", [ 999 | m("td", m("code", "N")), 1000 | m("td", "Go 5 years forward"), 1001 | ]), 1002 | m("tr", [ 1003 | m("td", m("code", "p")), 1004 | m("td", "Go to the previous year"), 1005 | ]), 1006 | m("tr", [ 1007 | m("td", m("code", "P")), 1008 | m("td", "Go 5 years back"), 1009 | ]), 1010 | m("tr", [ 1011 | m("td", m("code", "1-4")), 1012 | m("td", "Switch mark colors"), 1013 | ]), 1014 | ]), 1015 | ]), 1016 | ]) 1017 | } 1018 | } 1019 | 1020 | class OptionsDialogView implements m.ClassComponent<{ model: Model }> { 1021 | oncreate(vnode: m.VnodeDOM<{ model: Model }>) { 1022 | autofocusUnder(vnode.dom) 1023 | } 1024 | 1025 | view(vnode: m.Vnode<{ model: Model }>) { 1026 | const { model } = vnode.attrs 1027 | const markCount = Object.keys(model.markedDates).length 1028 | 1029 | return m(".dialog", [ 1030 | m("p", { style: { display: "flex", alignItems: "center" } }, [ 1031 | m(MarkColorInput, { 1032 | value: model.currentColor, 1033 | onNewValue(value) { 1034 | model.currentColor = value 1035 | }, 1036 | includeClear: false, 1037 | }), 1038 | ]), 1039 | m("p", m("label", [ 1040 | m("span", "Week starts on "), 1041 | m("select", { 1042 | value: model.weekStartsOn, 1043 | onchange(event: Event) { 1044 | model.weekStartsOn = (event.target as HTMLSelectElement).value === "Monday" ? "Monday" : "Sunday" 1045 | }, 1046 | }, [ 1047 | m("option", { value: "Sunday" }, "Sunday"), 1048 | m("option", { value: "Monday" }, "Monday"), 1049 | ]), 1050 | ])), 1051 | m("p", m("label", [ 1052 | m("input", { 1053 | type: "checkbox", 1054 | checked: model.weekNumbersEnabled, 1055 | onchange(event: Event) { 1056 | model.weekNumbersEnabled = (event.target as HTMLInputElement).checked 1057 | }, 1058 | }), 1059 | m("span", " Show week numbers"), 1060 | ])), 1061 | model.weekStartsOn !== "Monday" && model.weekNumbersEnabled && 1062 | m("p.info", [ 1063 | m(InfoIcon), 1064 | m("span", "Week numbers work best when weeks start on Mondays. "), 1065 | m("a", { 1066 | href: "#", 1067 | onclick(event: MouseEvent) { 1068 | event.preventDefault() 1069 | model.weekStartsOn = "Monday" 1070 | } 1071 | }, "Fix"), 1072 | ".", 1073 | ]), 1074 | m("p", m("label", [ 1075 | m("input", { 1076 | type: "checkbox", 1077 | checked: model.ghostDatesEnabled, 1078 | onchange(event: Event) { 1079 | model.ghostDatesEnabled = (event.target as HTMLInputElement).checked 1080 | }, 1081 | }), 1082 | m("span", " Show surrounding dates"), 1083 | ])), 1084 | markCount > 0 && [ 1085 | m("hr"), 1086 | m("p", m("button.danger", { 1087 | onclick() { 1088 | if (confirm(`Are you sure? This will delete your ${markCount} marks.`)) { 1089 | model.clearMarks() 1090 | } 1091 | }, 1092 | }, "Delete all marks, across all years")), 1093 | m("hr"), 1094 | m("h3", `Export ${markCount} mark${markCount > 1 ? "s" : ""}`), 1095 | m("p", [ 1096 | m("button", { 1097 | onclick() { 1098 | copyText(model.exportMarksToText()) 1099 | .then(() => { 1100 | const count = Object.keys(model.markedDates).length 1101 | showOSD(`Copied ${count} date${count > 1 ? "s" : ""} to clipboard`) 1102 | }) 1103 | }, 1104 | }, "Copy dates list"), 1105 | m("button", { 1106 | onclick() { 1107 | downloadText(model.exportMarksToText() + "\n") 1108 | }, 1109 | }, "Download"), 1110 | m("button", { 1111 | onclick() { 1112 | copyText(model.generateLinkWithMarks()) 1113 | .then(() => showOSD("Copied link to clipboard")) 1114 | }, 1115 | }, "Copy permalink") 1116 | ]), 1117 | ], 1118 | m("hr"), 1119 | m("h3", m.trust("Print β")), 1120 | m("p", m("label", [ 1121 | m("span", "Layout: "), 1122 | m("select", { 1123 | value: model.printLayout, 1124 | onchange(event: Event) { 1125 | const value = (event.target as HTMLSelectElement).value 1126 | if (value === "1" || value === "2" || value === "3" || value === "4" || value === "6" || value === "12") { 1127 | model.printLayout = value 1128 | } else { 1129 | model.printLayout = "2" 1130 | } 1131 | }, 1132 | }, [ 1133 | m("option", { value: "1" }, "1 page, all 12 months"), 1134 | m("option", { value: "2" }, "2 pages, 6 months in each"), 1135 | m("option", { value: "3" }, "3 pages, 4 months in each"), 1136 | m("option", { value: "4" }, "4 pages, 3 months in each"), 1137 | m("option", { value: "6" }, "6 pages, 2 months in each"), 1138 | m("option", { value: "12" }, "12 pages, 1 month in each"), 1139 | ]), 1140 | m("button", { 1141 | onclick() { 1142 | model.prepareAndPrint() 1143 | }, 1144 | }, [ 1145 | m(PrinterIcon), 1146 | m("span", "Print"), 1147 | ]), 1148 | ])), 1149 | m("button", { 1150 | class: "close-btn", 1151 | onclick() { 1152 | model.visibleDialog = null 1153 | }, 1154 | }, m.trust("×")), 1155 | ]) 1156 | } 1157 | } 1158 | 1159 | class MarkColorInput implements m.ClassComponent<{ value: string, onNewValue: (value: string) => void, includeClear: boolean }> { 1160 | view(vnode: m.Vnode<{ value: string, onNewValue: (value: string) => void, includeClear: boolean }>) { 1161 | const { value, onNewValue, includeClear } = vnode.attrs 1162 | return m("span.color-selector", [ 1163 | m("span", "Mark color: "), 1164 | includeClear && m("label", { title: "Clear" }, [ 1165 | m("input", { 1166 | type: "radio", 1167 | value: "", 1168 | checked: value === "", 1169 | onchange() { 1170 | onNewValue("") 1171 | }, 1172 | }), 1173 | m(Icon, { stroke: "currentColor", "stroke-width": 1, "stroke-linecap": "round" }, [ 1174 | m("line", { x1: 3, y1: 3, x2: 7, y2: 7 }), 1175 | m("line", { x1: 3, y1: 7, x2: 7, y2: 3 }), 1176 | value === "" && m("circle", { cx: 5, cy: 5, r: 4, fill: "none" }), 1177 | ]), 1178 | ]), 1179 | MARK_COLORS.map((color) => m("label", [ 1180 | m("input", { 1181 | type: "radio", 1182 | value: color, 1183 | checked: value === color, 1184 | onchange() { 1185 | onNewValue(color) 1186 | }, 1187 | }), 1188 | m(Icon, [ 1189 | m("circle", { cx: 5, cy: 5, r: 3, fill: color }), 1190 | value === color && m("circle", { cx: 5, cy: 5, r: 4, fill: "none", "stroke-width": 1, stroke: "currentColor" }), 1191 | ]), 1192 | ])), 1193 | ]) 1194 | } 1195 | } 1196 | 1197 | class StorageInfoView implements m.ClassComponent<{ model: Model }> { 1198 | isExpanded: boolean 1199 | 1200 | constructor() { 1201 | this.isExpanded = false 1202 | } 1203 | 1204 | view(vnode: m.Vnode<{ model: Model }>): m.Children { 1205 | const { model } = vnode.attrs 1206 | 1207 | if (model.markStorage !== "queryParams") { 1208 | return 1209 | } 1210 | 1211 | let localStorageUrl: string = "" 1212 | let localStorageMarkCount: number = 0 1213 | if (this.isExpanded) { 1214 | const url = new URL(location.toString()) 1215 | url.search = "" 1216 | localStorageUrl = url.toString() 1217 | localStorageMarkCount = model.getLocalStorageMarkCount() 1218 | } 1219 | 1220 | return m(".storage-info" + (this.isExpanded ? ".open" : ""), [ 1221 | m( 1222 | "a.summary", 1223 | { 1224 | href: "", 1225 | onclick: (event: MouseEvent) => { 1226 | event.preventDefault() 1227 | this.isExpanded = !this.isExpanded 1228 | }, 1229 | }, 1230 | [ 1231 | m("span", m.trust(this.isExpanded ? "▾" : "▸")), 1232 | m(InfoIcon), 1233 | m("span", "Marks stored in URL"), 1234 | ], 1235 | ), 1236 | this.isExpanded && [ 1237 | m("p", "All marked dates are stored in the URL, which can be copied to share/save elsewhere."), 1238 | m("p", [ 1239 | "Instead of the URL, marks can be saved to your local storage. ", 1240 | localStorageMarkCount > 0 1241 | ? `You already have ${localStorageMarkCount} date${localStorageMarkCount > 1 ? "s" : ""} marked there.` 1242 | : "You don't have any dates marked in your local storage yet though.", 1243 | " ", 1244 | m("a", { href: localStorageUrl }, "Click here to switch to local storage"), 1245 | "." 1246 | ]), 1247 | ] 1248 | ]) 1249 | } 1250 | } 1251 | 1252 | class ColorChangeOSDView implements m.ClassComponent<{ model: Model }> { 1253 | view (vnode: m.Vnode<{ model: Model }>): m.Children { 1254 | const { model } = vnode.attrs 1255 | return m(".color-change-osd", [ 1256 | m(MarkColorInput, { 1257 | value: model.currentColor, 1258 | onNewValue(value: string) { 1259 | model.currentColor = value 1260 | }, 1261 | includeClear: false, 1262 | }), 1263 | ]) 1264 | } 1265 | } 1266 | 1267 | function autofocusUnder(parent: Element): void { 1268 | (parent.querySelector("input, select, textarea") as HTMLElement)?.focus() 1269 | } 1270 | 1271 | function isWeekend(date: Date): boolean { 1272 | const day = date.getDay() 1273 | return day === 0 || day === 6 1274 | } 1275 | 1276 | function isSameDate(d1: null | Date, d2: null | Date): boolean { 1277 | return d1 != null 1278 | && d2 != null 1279 | && d1.getDate() === d2.getDate() 1280 | && d1.getMonth() === d2.getMonth() 1281 | && d1.getFullYear() === d2.getFullYear() 1282 | } 1283 | 1284 | function dateToBasicIso(date: null | Date): string { 1285 | return date == null ? "" : `${date.getFullYear()}${pad(1 + date.getMonth(), 2)}${pad(date.getDate(), 2)}` 1286 | } 1287 | 1288 | function dateToHumanReadable(date: null | Date): string { 1289 | return date == null ? "" : `${WEEKDAYS[date.getDay()]}, ${date.getDate()}${ordinalSuffix(date.getDate())} of ${MONTHS[date.getMonth()]}, ${date.getFullYear()}` 1290 | } 1291 | 1292 | function ordinalSuffix(n: number): string { 1293 | // This only works for numbers under 100, which is all we need. 1294 | const lastDigit = n % 10 1295 | 1296 | if (n != 11 && n != 12 && n != 13 && lastDigit > 0 && lastDigit < 4) { 1297 | return ["st", "nd", "rd"][lastDigit - 1] 1298 | } 1299 | 1300 | return "th" 1301 | } 1302 | 1303 | function pad(n: number | string, len: number): string { 1304 | let str = n.toString() 1305 | while (str.length < len) { 1306 | str = "0" + str 1307 | } 1308 | return str 1309 | } 1310 | 1311 | function parseDate(dateStr: string): null | Date { 1312 | dateStr = dateStr.toLowerCase() 1313 | 1314 | let d 1315 | if (dateStr === "today" || dateStr === "now") { 1316 | d = new Date() 1317 | } else if (dateStr.match(/^\d{8}$/)) { 1318 | d = new Date( 1319 | parseInt(dateStr.slice(0, 4), 10), 1320 | parseInt(dateStr.slice(4, 6), 10) - 1, 1321 | parseInt(dateStr.slice(6), 10), 1322 | ) 1323 | } else { 1324 | d = new Date(dateStr.replace(/-/g, ' ')) 1325 | } 1326 | 1327 | return isNaN(d.getTime()) ? null : d 1328 | } 1329 | 1330 | function formatDate(date: Date, format: string): string { 1331 | return format.replace(/%(.)/g, (match: string, code: string): string => { 1332 | switch (code) { 1333 | case "d": 1334 | return pad(date.getUTCDate(), 2) 1335 | case "m": 1336 | return pad(date.getUTCMonth() + 1, 2) 1337 | case "M": 1338 | return ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][date.getUTCMonth()] 1339 | case "Y": 1340 | return pad(date.getUTCFullYear(), 4) 1341 | } 1342 | return match 1343 | }) 1344 | } 1345 | 1346 | function computeWeekNumber(date: Date): number { 1347 | // Ref: . 1348 | const firstJan = new Date(date) 1349 | firstJan.setDate(1) 1350 | firstJan.setMonth(0) 1351 | 1352 | if (date.getMonth() === 11 /* December */ && date.getDate() > 28 /* Too few days of this year in this week */) { 1353 | // Here, we use the week number of the upcoming first Jan. 1354 | return computeWeekNumber(new Date(firstJan.getFullYear() + 1, 0, 1)) 1355 | } 1356 | 1357 | const dayCount = (normalizedValueOf(date) - normalizedValueOf(firstJan)) / (24 * 60 * 60 * 1000) 1358 | return (![0, 5, 6].includes(firstJan.getDay()) ? 1 : 0) + Math.ceil(dayCount / 7) 1359 | } 1360 | 1361 | function computeMessagesForDayCount(days: number): { weeks: null | string } { 1362 | let weeks = null 1363 | if (days >= 7) { 1364 | const fullWeeks = Math.floor(days / 7) 1365 | const remainingDays = days % 7 1366 | if (remainingDays === 3 || remainingDays === 4) { 1367 | weeks = fullWeeks + "½" 1368 | } else if (remainingDays > 4) { 1369 | weeks = "<" + (fullWeeks + 1) 1370 | } else if (remainingDays === 0) { 1371 | weeks = fullWeeks.toString() 1372 | } else { 1373 | weeks = ">" + fullWeeks 1374 | } 1375 | } 1376 | 1377 | return { 1378 | weeks, 1379 | } 1380 | } 1381 | 1382 | function normalizedValueOf(date: Date): number { 1383 | return new Date(date.getFullYear(), date.getMonth(), date.getDate()).valueOf() 1384 | } 1385 | 1386 | function dateAddDays(d: Date, delta: number): Date { 1387 | const d2 = new Date(d) 1388 | d2.setDate(d2.getDate() + delta) 1389 | return d2 1390 | } 1391 | 1392 | function copyText(text: string): Promise { 1393 | return navigator.clipboard.writeText(text) 1394 | .catch((reason) => alert("Error copying text: " + reason)) 1395 | } 1396 | 1397 | function showOSD(content: string) { 1398 | const osd = document.createElement("div") 1399 | osd.className = "osd" 1400 | osd.innerText = content 1401 | document.body.append(osd) 1402 | setTimeout(() => osd.remove(), 3000) 1403 | } 1404 | 1405 | export function downloadText(text: string, filename = "dates.txt"): void { 1406 | const el = document.createElement("a") 1407 | el.style.display = "none" 1408 | el.setAttribute("download", filename) 1409 | el.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text)) 1410 | document.body.append(el) 1411 | el.click() 1412 | el.remove() 1413 | } 1414 | 1415 | function flash(selector: string): void { 1416 | const el = document.querySelector(selector) 1417 | if (el == null) { 1418 | return 1419 | } 1420 | el.scrollIntoView({ block: "center" }) 1421 | el.addEventListener("animationend", clear) 1422 | el.classList.add("flash") 1423 | function clear() { 1424 | el?.classList.remove("flash") 1425 | el?.removeEventListener("animationend", clear) 1426 | } 1427 | } 1428 | -------------------------------------------------------------------------------- /src/icons/about.txt: -------------------------------------------------------------------------------- 1 | This favicon was generated using the following graphics from Twitter Twemoji: 2 | 3 | - Graphics Title: 1f5d3.svg 4 | - Graphics Author: Copyright 2020 Twitter, Inc and other contributors (https://github.com/twitter/twemoji) 5 | - Graphics Source: https://github.com/twitter/twemoji/blob/master/assets/svg/1f5d3.svg 6 | - Graphics License: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/) 7 | -------------------------------------------------------------------------------- /src/icons/favicon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharat87/just-a-calendar/4d143a3ccdbad0aef74b508b0f32af8778e96153/src/icons/favicon-16.png -------------------------------------------------------------------------------- /src/icons/favicon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharat87/just-a-calendar/4d143a3ccdbad0aef74b508b0f32af8778e96153/src/icons/favicon-180.png -------------------------------------------------------------------------------- /src/icons/favicon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharat87/just-a-calendar/4d143a3ccdbad0aef74b508b0f32af8778e96153/src/icons/favicon-192.png -------------------------------------------------------------------------------- /src/icons/favicon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharat87/just-a-calendar/4d143a3ccdbad0aef74b508b0f32af8778e96153/src/icons/favicon-32.png -------------------------------------------------------------------------------- /src/icons/favicon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharat87/just-a-calendar/4d143a3ccdbad0aef74b508b0f32af8778e96153/src/icons/favicon-512.png -------------------------------------------------------------------------------- /src/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharat87/just-a-calendar/4d143a3ccdbad0aef74b508b0f32af8778e96153/src/icons/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Just a Calendar. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/web-manifest-combined.json", 3 | "name": "Just a Calendar", 4 | "start_url": "/", 5 | "display": "standalone", 6 | "description": "A simple Calendar app.", 7 | "icons": [ 8 | { 9 | "src": "icons/favicon-512.png", 10 | "sizes": "512x512", 11 | "type": "image/png" 12 | }, 13 | { 14 | "src": "icons/favicon-180.png", 15 | "sizes": "180x180", 16 | "type": "image/png" 17 | }, 18 | { 19 | "src": "icons/favicon-192.png", 20 | "sizes": "192x192", 21 | "type": "image/png" 22 | }, 23 | { 24 | "src": "icons/favicon-16.png", 25 | "sizes": "16x16", 26 | "type": "image/png" 27 | }, 28 | { 29 | "src": "icons/favicon-32.png", 30 | "sizes": "32x32", 31 | "type": "image/png" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /src/scripts/ClockPageView.ts: -------------------------------------------------------------------------------- 1 | import m from "mithril" 2 | 3 | const Model = { 4 | isTicking: false, 5 | hoursHandAngle: 0, 6 | minutesHandAngle: 0, 7 | secondsHandAngle: 0, 8 | } 9 | 10 | function tick() { 11 | if (Model.isTicking) { 12 | requestAnimationFrame(tick) 13 | } 14 | 15 | const now = new Date() 16 | 17 | const seconds = now.getSeconds() + now.getMilliseconds() / 1000 18 | const minutes = now.getMinutes() + seconds / 60 19 | const hours = now.getHours() + minutes / 60 20 | 21 | Model.hoursHandAngle = hours * 30 22 | Model.minutesHandAngle = minutes * 6 23 | Model.secondsHandAngle = seconds * 6 24 | 25 | m.redraw() 26 | } 27 | 28 | export default class ClockPageView implements m.ClassComponent { 29 | oninit() { 30 | Model.isTicking = true 31 | tick() 32 | } 33 | 34 | onremove() { 35 | Model.isTicking = false 36 | } 37 | 38 | view(): m.Children { 39 | return [ 40 | m(ClockView), 41 | m(SmallCalendarView), 42 | ] 43 | } 44 | } 45 | 46 | class ClockView implements m.ClassComponent { 47 | view(): m.Children { 48 | const hourMarks = [] 49 | for (let i = 0; i < 12; i++) { 50 | hourMarks.push(m("line", { 51 | x1: 50, 52 | y1: 3, 53 | x2: 50, 54 | y2: 5.5, 55 | stroke: "currentColor", 56 | "stroke-width": .8, 57 | transform: `rotate(${i * 30})`, 58 | "transform-origin": "center center", 59 | })) 60 | } 61 | 62 | const minuteMarks = [] 63 | for (let i = 0; i < 60; i++) { 64 | minuteMarks.push(m("line", { 65 | x1: 50, 66 | y1: 3, 67 | x2: 50, 68 | y2: 4.5, 69 | stroke: "currentColor", 70 | "stroke-width": .4, 71 | transform: `rotate(${i * 6})`, 72 | "transform-origin": "center center", 73 | })) 74 | } 75 | 76 | return [ 77 | m("svg", { 78 | version: "1.1", 79 | width: "300", 80 | height: "300", 81 | viewBox: "0 0 100 100", 82 | xmlns: "http://www.w3.org/2000/svg", 83 | }, [ 84 | m("circle", { 85 | cx: "50", 86 | cy: "50", 87 | r: "47", 88 | fill: "none", 89 | stroke: "currentColor", 90 | "stroke-width": 1, 91 | }), 92 | ...hourMarks, 93 | ...minuteMarks, 94 | // Hours hand. 95 | m("line", { 96 | x1: 50, 97 | y1: 50, 98 | x2: 50, 99 | y2: 25, 100 | stroke: "currentColor", 101 | "stroke-width": 1, 102 | transform: `rotate(${Model.hoursHandAngle})`, 103 | "transform-origin": "center center", 104 | }), 105 | // Minutes hand. 106 | m("line", { 107 | x1: 50, 108 | y1: 50, 109 | x2: 50, 110 | y2: 14, 111 | stroke: "currentColor", 112 | "stroke-width": .7, 113 | transform: `rotate(${Model.minutesHandAngle})`, 114 | "transform-origin": "center center", 115 | }), 116 | // Seconds hand. 117 | m("line", { 118 | x1: 50, 119 | y1: 55, 120 | x2: 50, 121 | y2: 10, 122 | stroke: "currentColor", 123 | "stroke-width": .3, 124 | transform: `rotate(${Model.secondsHandAngle})`, 125 | "transform-origin": "center center", 126 | }), 127 | // Central dot 128 | m("circle", { 129 | cx: 50, 130 | cy: 50, 131 | r: 1, 132 | fill: "currentColor", 133 | stroke: "none", 134 | }), 135 | ]), 136 | ] 137 | } 138 | } 139 | 140 | class SmallCalendarView implements m.ClassComponent { 141 | view(): m.Children { 142 | const weekRows = [] 143 | const date = new Date() 144 | 145 | const currentMonth = date.getMonth() 146 | const currentDate = date.getDate() 147 | 148 | date.setDate(1) // Go to the start of the month. 149 | date.setDate(1 - date.getDay()) // Go the most recent past Sunday, or no change if already on a Sunday. 150 | 151 | while (true) { 152 | const row = [] 153 | while (true) { 154 | row.push(m("td", { 155 | class: [ 156 | date.getMonth() === currentMonth ? "" : "dull", 157 | date.getMonth() === currentMonth && date.getDate() === currentDate ? "active" : "", 158 | ].join("") || undefined, 159 | }, date.getDate())) 160 | date.setDate(date.getDate() + 1) 161 | if (date.getDay() === 0) { 162 | break 163 | } 164 | } 165 | weekRows.push(m("tr", row)) 166 | if (date.getMonth() !== currentMonth) { 167 | break 168 | } 169 | } 170 | 171 | return m(".small-calendar", [ 172 | m("h2", [ 173 | ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][currentMonth], 174 | " ", 175 | new Date().getFullYear(), 176 | ]), 177 | m("table.month", [ 178 | m("thead", m("tr", ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map(s => m("th", s)))), 179 | m("tbody", weekRows), 180 | ]), 181 | ]) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/scripts/migrate.ts: -------------------------------------------------------------------------------- 1 | const OLD_DOMAIN = "cal.sharats.me" 2 | const NEW_DOMAIN = "justacalendar.app" 3 | 4 | export function needsMigrate(): boolean { 5 | // If this is the old domain, don't load the app, just migrate. 6 | if (location.host === OLD_DOMAIN) { 7 | initiateMigrate() 8 | return true 9 | } 10 | 11 | // When in a frame, prepare to accept migrate messages from old-domain, but otherwise let the app load. This is so 12 | // that embedding this app in other websites is possible, if needed. 13 | if (window.self !== window.top) { 14 | // Running in a frame. 15 | acceptMigrate() 16 | } 17 | 18 | return false 19 | } 20 | 21 | // Here's how this works: 22 | // 1. If there's no data in localStorage (other than backup data from step 6), move to step 7. 23 | // 2. Load up the new domain in a frame. 24 | // 3. When the frame loads, send the migration data to it. 25 | // 4. When the frame receives the migration data, it will save this data to it's localStorage. 26 | // 5. Receive an okay message from the frame. 27 | // 6. Move all data on old domain to a backup namespace. 28 | // 7. Redirect to the new domain. 29 | 30 | type MigrateStorage = { 31 | currentColor: null | string 32 | ghostMode: null | string 33 | marksV2: null | string 34 | weekNumbersEnabled: null | string 35 | weekStartsOn: null | string 36 | } 37 | 38 | function initiateMigrate() { 39 | const frame = document.createElement("iframe") 40 | frame.src = `https://${NEW_DOMAIN}/` 41 | frame.style.display = "none" 42 | 43 | frame.addEventListener("load", () => { 44 | if (frame.contentWindow == null) { 45 | console.error("Cannot access contentWindow on the new domain frame.") 46 | return 47 | } 48 | frame.contentWindow.postMessage({ 49 | type: "migrate", 50 | storage: { 51 | currentColor: localStorage.getItem("currentColor"), 52 | ghostMode: localStorage.getItem("ghostMode"), 53 | marksV2: localStorage.getItem("marksV2"), 54 | weekNumbersEnabled: localStorage.getItem("weekNumbersEnabled"), 55 | weekStartsOn: localStorage.getItem("weekStartsOn"), 56 | }, 57 | }, `https://${NEW_DOMAIN}/`) 58 | }) 59 | 60 | window.addEventListener("message", (event: MessageEvent) => { 61 | console.log("top received message", event.origin, event.data) 62 | if (event.origin !== "https://" + NEW_DOMAIN) { 63 | console.error("Message from unexpected origin", event.origin) 64 | return 65 | } 66 | 67 | localStorage.clear() 68 | 69 | document.body.insertAdjacentHTML( 70 | "beforeend", 71 | `

Done. Bye bye!

`, 72 | ) 73 | 74 | setTimeout(() => { 75 | window.location.href = `https://${NEW_DOMAIN}/` 76 | }, 1000) 77 | }) 78 | 79 | document.body.appendChild(frame) 80 | document.body.insertAdjacentHTML( 81 | "beforeend", 82 | `
Migrating to ${NEW_DOMAIN}… please hold on.
`, 83 | ) 84 | } 85 | 86 | function acceptMigrate() { 87 | window.addEventListener("message", (event: MessageEvent) => { 88 | console.log("frame received message", event.origin, event.data) 89 | if (event.origin !== "https://" + OLD_DOMAIN) { 90 | console.error("Message from unexpected origin", event.origin) 91 | return 92 | } 93 | if (event.source == null) { 94 | console.error("Cannot access source on the old-domain parent.") 95 | return 96 | } 97 | 98 | if (event.data.type !== "migrate") { 99 | console.error("Unexpected message type", event.data) 100 | return 101 | } 102 | 103 | const storage: MigrateStorage = event.data.storage 104 | 105 | if (storage.currentColor != null) { 106 | localStorage.setItem("currentColor", storage.currentColor) 107 | } 108 | 109 | if (storage.ghostMode != null) { 110 | localStorage.setItem("ghostMode", storage.ghostMode) 111 | } 112 | 113 | if (storage.marksV2 != null) { 114 | mergeMarks(JSON.parse(storage.marksV2)) 115 | } 116 | 117 | if (storage.weekNumbersEnabled != null) { 118 | localStorage.setItem("weekNumbersEnabled", storage.weekNumbersEnabled) 119 | } 120 | 121 | if (storage.weekStartsOn != null) { 122 | localStorage.setItem("weekStartsOn", storage.weekStartsOn) 123 | } 124 | 125 | event.source.postMessage({ ok: true }, { 126 | targetOrigin: "https://" + OLD_DOMAIN, 127 | }) 128 | }) 129 | } 130 | 131 | function mergeMarks(incomingMarks: [date: string, color: string][]) { 132 | const marksMap: Record = {} 133 | 134 | for (const [date, color] of JSON.parse(localStorage.marksV2 || "[]")) { 135 | marksMap[date] = color 136 | } 137 | 138 | for (const [date, color] of incomingMarks) { 139 | marksMap[date] = color 140 | } 141 | 142 | const marks: [date: string, color: string][] = [] 143 | for (const [date, color] of Object.entries(marksMap)) { 144 | marks.push([date, color]) 145 | } 146 | 147 | localStorage.setItem("marksV2", JSON.stringify(marks)) 148 | } 149 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | @custom-media --dark (prefers-color-scheme: dark); 2 | 3 | * { 4 | scrollbar-color: currentColor transparent; 5 | scrollbar-width: thin; 6 | } 7 | 8 | html { 9 | --bg-color: white; 10 | --bg-color-alt: #F7F7F7; 11 | --bg-color-hover: #09F; 12 | --fg-color: black; 13 | --fg-color-hover: white; 14 | --highlight0: #F8F8F8; 15 | --highlight1: #E5E5E5; 16 | --highlight2: #BBB; 17 | background-color: var(--bg-color); 18 | color: var(--fg-color); 19 | font-family: Nunito, sans-serif; 20 | font-size: 18px; 21 | overflow-y: scroll; 22 | color-scheme: light dark; 23 | 24 | @media (--dark) { 25 | --bg-color: #444; 26 | --bg-color-alt: #333; 27 | --fg-color: white; 28 | --highlight1: #555; 29 | --highlight2: #777; 30 | } 31 | } 32 | 33 | body { 34 | margin: 0; 35 | min-height: 100vh; 36 | } 37 | 38 | .page-calendar { 39 | margin: 0 auto; 40 | max-width: 1100px; 41 | } 42 | 43 | h1 { 44 | margin: 9px 0 0; 45 | letter-spacing: -1px; 46 | } 47 | 48 | h1 + p { 49 | margin-top: 3px; 50 | } 51 | 52 | h1, h2, .center { 53 | text-align: center; 54 | } 55 | 56 | h3 { 57 | margin-bottom: 0; 58 | 59 | & + p { 60 | margin-top: 3px; 61 | } 62 | } 63 | 64 | code { 65 | font-family: Consolas, Menlo, 'Roboto Mono', monospace; 66 | font-size: inherit; 67 | } 68 | 69 | a { 70 | color: #09F; 71 | } 72 | 73 | input, select { 74 | font: inherit; 75 | background: transparent; 76 | color: inherit; 77 | border: 1px solid var(--highlight2); 78 | } 79 | 80 | button { 81 | color: inherit; 82 | --bg-top: #0000; 83 | --bg-bot: #0001; 84 | --border: #0002; 85 | background-image: linear-gradient(var(--bg-top), var(--bg-bot)); 86 | background-color: transparent; 87 | border: 1px solid var(--border); 88 | padding: 3px 12px; 89 | border-radius: 2px; 90 | margin: 3px; 91 | min-width: 2em; 92 | font: inherit; 93 | cursor: pointer; 94 | box-shadow: 0 1px 2px var(--border); 95 | 96 | &:hover { 97 | --bg-top: #0001; 98 | --bg-bot: #0002; 99 | --border: #0004; 100 | 101 | &.danger { 102 | background-color: maroon; 103 | color: #fff; 104 | } 105 | } 106 | 107 | &:active { 108 | --bg-bot: var(--bg-top); 109 | } 110 | 111 | @media (--dark) { 112 | --bg-top: #fff3; 113 | --bg-bot: #fff1; 114 | 115 | &:hover { 116 | --bg-top: #fff4; 117 | --bg-bot: #fff2; 118 | } 119 | } 120 | 121 | &:first-child { 122 | margin-left: 0; 123 | } 124 | } 125 | 126 | .info { 127 | background-color: #0002; 128 | padding: 6px; 129 | border-radius: 3px; 130 | } 131 | 132 | .year-input { 133 | width: 5ch; 134 | text-align: center; 135 | appearance: textfield; 136 | border-radius: 2px; 137 | box-shadow: inset 0 0 2px #0006; 138 | margin: 3px; 139 | } 140 | 141 | .calendar { 142 | display: flex; 143 | flex-wrap: wrap; 144 | justify-content: center; 145 | margin-top: -1em; 146 | } 147 | 148 | .month { 149 | margin: 1em; 150 | } 151 | 152 | .controls { 153 | margin: .5em; 154 | display: flex; 155 | justify-content: center; 156 | flex-wrap: wrap; 157 | } 158 | 159 | table { 160 | border-collapse: collapse; 161 | } 162 | 163 | td, th { 164 | border: 1px solid var(--highlight1); 165 | padding: .2em .4em; 166 | } 167 | 168 | td.date { 169 | text-align: right; 170 | } 171 | 172 | td.date { 173 | cursor: pointer; 174 | position: relative; 175 | } 176 | 177 | .week-num { 178 | cursor: pointer; 179 | text-align: right; 180 | font-size: .8em; 181 | } 182 | 183 | .weekend { 184 | background-color: var(--highlight1); 185 | } 186 | 187 | .today { 188 | outline: 3px solid crimson; 189 | z-index: 3; 190 | } 191 | 192 | .diff-month { 193 | opacity: .4; 194 | visibility: hidden; 195 | } 196 | 197 | .ghosts .diff-month { 198 | visibility: visible; 199 | } 200 | 201 | .mark { 202 | color: white; 203 | } 204 | 205 | .mark-coral { 206 | background: coral; 207 | } 208 | 209 | .mark-deeppink { 210 | background: deeppink; 211 | } 212 | 213 | .mark-green { 214 | background: green; 215 | } 216 | 217 | .mark-purple { 218 | background: purple; 219 | } 220 | 221 | td.date.drag-start { 222 | outline: 3px solid #07f; 223 | z-index: 4; 224 | } 225 | 226 | td.vsep, td.hsep { 227 | border: none; 228 | } 229 | 230 | .bubble { 231 | display: inline-block; 232 | width: 6px; 233 | height: 6px; 234 | border-radius: 3px; 235 | background-color: gray; 236 | position: absolute; 237 | left: 3px; 238 | } 239 | 240 | .bubble.fixed-holiday { 241 | background-color: red; 242 | } 243 | 244 | .bubble.optional-holiday { 245 | background-color: #F90; 246 | } 247 | 248 | .settings { 249 | margin: 1em; 250 | padding: 3px; 251 | display: flex; 252 | justify-content: center; 253 | } 254 | 255 | .settings > * { 256 | margin: 0 .5em; 257 | } 258 | 259 | .popup { 260 | background-color: var(--bg-color-alt); 261 | display: none; 262 | } 263 | 264 | .popup.show { 265 | display: block; 266 | } 267 | 268 | .date-list { 269 | background-color: transparent; 270 | color: inherit; 271 | font: inherit; 272 | border: none; 273 | padding: 6px; 274 | } 275 | 276 | .date-list:focus { 277 | outline: none; 278 | } 279 | 280 | svg.i { 281 | width: 1.3em; 282 | height: 1.3em; 283 | vertical-align: middle; 284 | } 285 | 286 | .color-selector { 287 | display: flex; 288 | align-items: center; 289 | 290 | & > :first-child { 291 | margin-right: 6px; 292 | } 293 | 294 | & svg { 295 | cursor: pointer; 296 | } 297 | 298 | & > label { 299 | display: inline-flex; 300 | } 301 | 302 | & input[type=radio] { 303 | display: none; 304 | } 305 | 306 | @nest .cmenu & { 307 | padding: 6px 12px; 308 | } 309 | } 310 | 311 | .cmenu { 312 | position: absolute; 313 | box-shadow: 0 3px 42px #0008; 314 | z-index: 5; 315 | font-size: .9em; 316 | margin-left: 1px; 317 | border-radius: 0 3px 3px; 318 | overflow: hidden; 319 | } 320 | 321 | .cmenu a { 322 | text-decoration: none; 323 | color: inherit; 324 | padding: 6px 12px; 325 | display: block; 326 | } 327 | 328 | .cmenu a:hover { 329 | background-color: var(--bg-color-hover); 330 | color: var(--fg-color-hover); 331 | } 332 | 333 | .has-cmenu { 334 | z-index: 8; 335 | background: var(--bg-color-alt); 336 | color: var(--fg-color); 337 | } 338 | 339 | .dialog { 340 | display: block; 341 | position: fixed; 342 | background-color: var(--bg-color-alt); 343 | box-shadow: 6px 6px 36px #0005; 344 | padding: 1em; 345 | border-radius: 6px; 346 | top: 2em; 347 | left: 50%; 348 | transform: translateX(-50%); 349 | max-height: calc(100vh - 6em); 350 | overflow: auto; 351 | 352 | & .info { 353 | max-width: 360px; 354 | } 355 | 356 | @media (width <= 600px) { 357 | left: 0; 358 | right: 0; 359 | border-radius: 0; 360 | transform: none; 361 | } 362 | } 363 | 364 | .help-dialog { 365 | left: 2em; 366 | transform: none; 367 | } 368 | 369 | footer { 370 | text-align: center; 371 | border-top: 1px solid var(--highlight1); 372 | margin: 3em 0; 373 | font-size: .9em; 374 | display: flex; 375 | flex-wrap: wrap; 376 | justify-content: space-between; 377 | } 378 | 379 | footer p { 380 | margin: .5em 0 1em; 381 | } 382 | 383 | .drag-date-period { 384 | position: fixed; 385 | display: block; 386 | pointer-events: none; 387 | background: var(--fg-color); 388 | color: var(--bg-color); 389 | padding: 3px 9px; 390 | border-radius: 3px; 391 | box-shadow: 0 0 9px #0009; 392 | z-index: 9; 393 | list-style: none; 394 | transform: translateY(12px); 395 | } 396 | 397 | .drag-date-period.up { 398 | transform: translateY(-100%) translateY(-24px); 399 | } 400 | 401 | .close-btn { 402 | display: block; 403 | position: absolute; 404 | top: 6px; 405 | right: 6px; 406 | border-radius: 50%; 407 | background: none; 408 | border: none; 409 | box-shadow: none; 410 | 411 | &:hover { 412 | color: #f20; 413 | background: none; 414 | } 415 | } 416 | 417 | .storage-info { 418 | position: fixed; 419 | bottom: 6px; 420 | right: 6px; 421 | background-color: #07f; 422 | color: #fff; 423 | border-radius: 3px; 424 | max-width: 400px; 425 | 426 | &.open { 427 | box-shadow: 0 0 96px #0005; 428 | } 429 | 430 | & a.summary { 431 | padding: 3px 6px; 432 | text-decoration: none; 433 | display: flex; 434 | place-items: center; 435 | 436 | & :not(:first-child) { 437 | margin-left: 6px; 438 | } 439 | } 440 | 441 | & a { 442 | color: inherit; 443 | } 444 | 445 | & p { 446 | margin: 1em; 447 | } 448 | 449 | @media only print { 450 | display: none; 451 | } 452 | } 453 | 454 | .color-change-osd { 455 | position: fixed; 456 | top: 1em; 457 | right: 1em; 458 | background-color: var(--bg-color-alt); 459 | padding: 1em; 460 | border-radius: 6px; 461 | box-shadow: 12px 12px 72px #0005; 462 | animation: toast .2s; 463 | } 464 | 465 | .osd { 466 | font-size: 1.2em; 467 | color: #fff; 468 | background-color: #222E; 469 | padding: .5em 1em; 470 | border-radius: 6px; 471 | position: fixed; 472 | top: 30%; 473 | left: 50%; 474 | transform: translate(-50%, -50%); 475 | } 476 | 477 | @keyframes toast { 478 | from { 479 | transform: translateX(100%); 480 | } 481 | to { 482 | transform: translateX(0); 483 | } 484 | } 485 | 486 | @media only screen { 487 | 488 | .print { 489 | display: none; 490 | } 491 | 492 | h2 { 493 | margin: 1em 0 6px; 494 | } 495 | 496 | hr { 497 | border: none; 498 | border-top: 1px solid currentColor; 499 | } 500 | 501 | } 502 | 503 | @media only print { 504 | 505 | .screen, .dialog { 506 | display: none; 507 | } 508 | 509 | h1 { 510 | font-size: 21pt; 511 | margin: .3in -.5in 0; 512 | } 513 | 514 | h2 { 515 | font-size: 18pt; 516 | margin: .1in 0; 517 | } 518 | 519 | h1:not(:first-child) { 520 | page-break-before: always; 521 | } 522 | 523 | body[data-print-layout="2"] { 524 | font-size: 14pt; 525 | } 526 | 527 | body[data-print-layout="3"] { 528 | font-size: 16pt; 529 | } 530 | 531 | body[data-print-layout="4"] { 532 | font-size: 16pt; 533 | } 534 | 535 | body[data-print-layout="6"] { 536 | font-size: 21pt; 537 | } 538 | 539 | body[data-print-layout="12"] { 540 | font-size: 30pt; 541 | } 542 | 543 | .calendar { 544 | /* Unfortunately, `flex` display screws up print layouts 10x. */ 545 | display: block; 546 | text-align: center; 547 | } 548 | 549 | .today { 550 | outline: none; 551 | } 552 | 553 | .month { 554 | margin: .4em 1.2em; 555 | display: inline-block; 556 | page-break-inside: avoid; 557 | } 558 | 559 | .weekend { 560 | background: none; 561 | } 562 | 563 | hr { 564 | visibility: hidden; 565 | } 566 | 567 | } 568 | 569 | .flash { 570 | animation: flash .4s; 571 | } 572 | @keyframes flash { 573 | 0% { 574 | transform: scale(1); 575 | outline: 0 solid red; 576 | box-shadow: 0 0 0 #0008; 577 | } 578 | 50% { 579 | transform: scale(3); 580 | outline: 2px solid red; 581 | box-shadow: 0 0 12px #0008; 582 | } 583 | 100% { 584 | transform: scale(1); 585 | outline: 0 solid red; 586 | box-shadow: 0 0 0 #0008; 587 | } 588 | } 589 | 590 | .page-clock { 591 | height: 100vh; 592 | max-width: 160vh; 593 | margin: 0 auto; 594 | display: flex; 595 | place-items: center; 596 | place-content: space-evenly; 597 | 598 | & svg { 599 | width: 50vw; 600 | height: 60vh; 601 | } 602 | 603 | & .small-calendar { 604 | font-size: 4vh; 605 | 606 | & th { 607 | font-family: monospace; 608 | } 609 | 610 | & td { 611 | text-align: right; 612 | } 613 | 614 | & .active { 615 | outline: 3px solid crimson; 616 | } 617 | 618 | & .dull { 619 | opacity: .4; 620 | } 621 | } 622 | } 623 | -------------------------------------------------------------------------------- /src/sw.js: -------------------------------------------------------------------------------- 1 | // This import unambiguously indicates this script as a service-worker to Parcel. 2 | import "@parcel/service-worker" 3 | 4 | // Offline support. 5 | const CACHE_NAME = "just-a-calendar-cache" 6 | addEventListener("install", (event) => { 7 | event.waitUntil((async () => { 8 | const cache = await caches.open(CACHE_NAME) 9 | await cache.addAll(["/", "/index.html"]) 10 | })()) 11 | }) 12 | 13 | // A fetch handler is required for PWA to be detected. 14 | // We also use it to respond with cached copies of resources, if available, for offline support. 15 | addEventListener("fetch", (event) => { 16 | event.respondWith((async () => { 17 | try { 18 | const response = await fetch(event.request) 19 | const cache = await caches.open(CACHE_NAME) 20 | cache.put(event.request, response.clone()) 21 | .catch((reason) => console.error("Error caching response", reason)) 22 | return response 23 | } catch (error) { 24 | const cacheResponse = await caches.match(event.request) 25 | if (cacheResponse) { 26 | return cacheResponse 27 | } 28 | throw error 29 | } 30 | })()) 31 | }) 32 | 33 | // Clear old/unused caches, if any. 34 | addEventListener("activate", (event) => { 35 | event.waitUntil(caches.keys().then((keyList) => { 36 | return Promise.all(keyList.map((key) => { 37 | if (key === CACHE_NAME) { return } 38 | return caches.delete(key) 39 | })) 40 | })) 41 | }) 42 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "esModuleInterop": true, 5 | "strictNullChecks": true, 6 | "strictPropertyInitialization": true, 7 | "skipLibCheck": true, 8 | "noImplicitAny": true, 9 | "module": "ES2020", 10 | "isolatedModules": true, 11 | "lib": [ 12 | "ES2017", 13 | "DOM" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.16.7" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" 8 | integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== 9 | dependencies: 10 | "@babel/highlight" "^7.16.7" 11 | 12 | "@babel/helper-validator-identifier@^7.16.7": 13 | version "7.16.7" 14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" 15 | integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== 16 | 17 | "@babel/highlight@^7.16.7": 18 | version "7.16.10" 19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" 20 | integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== 21 | dependencies: 22 | "@babel/helper-validator-identifier" "^7.16.7" 23 | chalk "^2.0.0" 24 | js-tokens "^4.0.0" 25 | 26 | "@lezer/common@^0.15.0", "@lezer/common@^0.15.7": 27 | version "0.15.12" 28 | resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.12.tgz#2f21aec551dd5fd7d24eb069f90f54d5bc6ee5e9" 29 | integrity sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig== 30 | 31 | "@lezer/lr@^0.15.4": 32 | version "0.15.8" 33 | resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.8.tgz#1564a911e62b0a0f75ca63794a6aa8c5dc63db21" 34 | integrity sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg== 35 | dependencies: 36 | "@lezer/common" "^0.15.0" 37 | 38 | "@lmdb/lmdb-darwin-arm64@2.7.11": 39 | version "2.7.11" 40 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz#b717e72f023d4215d14e4c57433c711a53c782cf" 41 | integrity sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw== 42 | 43 | "@lmdb/lmdb-darwin-x64@2.7.11": 44 | version "2.7.11" 45 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz#b42898b0742b4a82b8224b742b2d174c449cd170" 46 | integrity sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q== 47 | 48 | "@lmdb/lmdb-linux-arm64@2.7.11": 49 | version "2.7.11" 50 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz#a8dc8e386d27006cfccbf2a8598290b63d03a9ec" 51 | integrity sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A== 52 | 53 | "@lmdb/lmdb-linux-arm@2.7.11": 54 | version "2.7.11" 55 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz#2103f48af28336efccaac008fe882dfce33e4ac5" 56 | integrity sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw== 57 | 58 | "@lmdb/lmdb-linux-x64@2.7.11": 59 | version "2.7.11" 60 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz#d21ac368022a662610540f2ba8bb6ff0b96a9940" 61 | integrity sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng== 62 | 63 | "@lmdb/lmdb-win32-x64@2.7.11": 64 | version "2.7.11" 65 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz#af2cb4ae6d3a92ecdeb1503b73079417525476d2" 66 | integrity sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng== 67 | 68 | "@mischnic/json-sourcemap@^0.1.0": 69 | version "0.1.0" 70 | resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507" 71 | integrity sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA== 72 | dependencies: 73 | "@lezer/common" "^0.15.7" 74 | "@lezer/lr" "^0.15.4" 75 | json5 "^2.2.1" 76 | 77 | "@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2": 78 | version "3.0.2" 79 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz#44d752c1a2dc113f15f781b7cc4f53a307e3fa38" 80 | integrity sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ== 81 | 82 | "@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2": 83 | version "3.0.2" 84 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz#f954f34355712212a8e06c465bc06c40852c6bb3" 85 | integrity sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw== 86 | 87 | "@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2": 88 | version "3.0.2" 89 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz#45c63037f045c2b15c44f80f0393fa24f9655367" 90 | integrity sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg== 91 | 92 | "@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2": 93 | version "3.0.2" 94 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz#35707efeafe6d22b3f373caf9e8775e8920d1399" 95 | integrity sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA== 96 | 97 | "@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2": 98 | version "3.0.2" 99 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz#091b1218b66c341f532611477ef89e83f25fae4f" 100 | integrity sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA== 101 | 102 | "@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2": 103 | version "3.0.2" 104 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407" 105 | integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ== 106 | 107 | "@parcel/bundler-default@2.9.1": 108 | version "2.9.1" 109 | resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.9.1.tgz#70a4f6e85d5e37c949b154ab0f518868a6aa8ab0" 110 | integrity sha512-gNTaSQpp7jiFvkQ/P/KfAiVLT3UOEs5bBivQm4OMdgSi2DTIsjGMQVQ7JDzvzEzrHiFlDmdXKxUagex54pOtJg== 111 | dependencies: 112 | "@parcel/diagnostic" "2.9.1" 113 | "@parcel/graph" "2.9.1" 114 | "@parcel/hash" "2.9.1" 115 | "@parcel/plugin" "2.9.1" 116 | "@parcel/utils" "2.9.1" 117 | nullthrows "^1.1.1" 118 | 119 | "@parcel/cache@2.9.1": 120 | version "2.9.1" 121 | resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.9.1.tgz#feb9191306e20fd9bc6f228138e2508cc276485d" 122 | integrity sha512-2aFWUAi7vkcnIdfOw3oW/vhgvwv9MPb+LjmJSkE59nNUuSJe83jJFAPAhqQTHd9L3kX/Xk+xJBNYNubUq/Cieg== 123 | dependencies: 124 | "@parcel/fs" "2.9.1" 125 | "@parcel/logger" "2.9.1" 126 | "@parcel/utils" "2.9.1" 127 | lmdb "2.7.11" 128 | 129 | "@parcel/codeframe@2.9.1": 130 | version "2.9.1" 131 | resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.9.1.tgz#ffd4dcba0f28ca95d04962abec8ff7d625b413c4" 132 | integrity sha512-qLVIyEHuZq8wWYaXVAwxMzlK3QqWlaB5fUSe1n+kITEa9EEwb2WPmysYAsWiVaFdD62A0+1klJ8Sq9gapOMIng== 133 | dependencies: 134 | chalk "^4.1.0" 135 | 136 | "@parcel/compressor-raw@2.9.1": 137 | version "2.9.1" 138 | resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.9.1.tgz#31da509506b4f848a061dd9b88a0ab5c049f4045" 139 | integrity sha512-aUkZ0pOzGjQ9kyaUQ/suDVmU5lR4mT9fU5HXlp3hGD7MWh2HFJUOfQ3gp5g3P9x+MeVZKU+ht6UcIMhrzelLGQ== 140 | dependencies: 141 | "@parcel/plugin" "2.9.1" 142 | 143 | "@parcel/config-default@2.9.1": 144 | version "2.9.1" 145 | resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.9.1.tgz#0dcc7ceea49d1391dfdb8e400d621837b7ccd24f" 146 | integrity sha512-oH6NHKaKp2YBHOcQJxwHGPbgGCZZZH1I4eef+KRBFiabgiDQxHLni+vg+c+mErd8lFrNn2gcGIdKzQwWqavT+w== 147 | dependencies: 148 | "@parcel/bundler-default" "2.9.1" 149 | "@parcel/compressor-raw" "2.9.1" 150 | "@parcel/namer-default" "2.9.1" 151 | "@parcel/optimizer-css" "2.9.1" 152 | "@parcel/optimizer-htmlnano" "2.9.1" 153 | "@parcel/optimizer-image" "2.9.1" 154 | "@parcel/optimizer-svgo" "2.9.1" 155 | "@parcel/optimizer-swc" "2.9.1" 156 | "@parcel/packager-css" "2.9.1" 157 | "@parcel/packager-html" "2.9.1" 158 | "@parcel/packager-js" "2.9.1" 159 | "@parcel/packager-raw" "2.9.1" 160 | "@parcel/packager-svg" "2.9.1" 161 | "@parcel/reporter-dev-server" "2.9.1" 162 | "@parcel/resolver-default" "2.9.1" 163 | "@parcel/runtime-browser-hmr" "2.9.1" 164 | "@parcel/runtime-js" "2.9.1" 165 | "@parcel/runtime-react-refresh" "2.9.1" 166 | "@parcel/runtime-service-worker" "2.9.1" 167 | "@parcel/transformer-babel" "2.9.1" 168 | "@parcel/transformer-css" "2.9.1" 169 | "@parcel/transformer-html" "2.9.1" 170 | "@parcel/transformer-image" "2.9.1" 171 | "@parcel/transformer-js" "2.9.1" 172 | "@parcel/transformer-json" "2.9.1" 173 | "@parcel/transformer-postcss" "2.9.1" 174 | "@parcel/transformer-posthtml" "2.9.1" 175 | "@parcel/transformer-raw" "2.9.1" 176 | "@parcel/transformer-react-refresh-wrap" "2.9.1" 177 | "@parcel/transformer-svg" "2.9.1" 178 | 179 | "@parcel/core@2.9.1": 180 | version "2.9.1" 181 | resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.9.1.tgz#26261b6d76acbf3e8a69553f0ef36aac0b2a3621" 182 | integrity sha512-D/7iyRV5c8kYMV1JGkokktxh3ON5CMvNAllaBucl4SMatAyLo5aLjGG5ey6FD/4Tv+JJ6NsldLtkvciDVJdgFQ== 183 | dependencies: 184 | "@mischnic/json-sourcemap" "^0.1.0" 185 | "@parcel/cache" "2.9.1" 186 | "@parcel/diagnostic" "2.9.1" 187 | "@parcel/events" "2.9.1" 188 | "@parcel/fs" "2.9.1" 189 | "@parcel/graph" "2.9.1" 190 | "@parcel/hash" "2.9.1" 191 | "@parcel/logger" "2.9.1" 192 | "@parcel/package-manager" "2.9.1" 193 | "@parcel/plugin" "2.9.1" 194 | "@parcel/profiler" "2.9.1" 195 | "@parcel/source-map" "^2.1.1" 196 | "@parcel/types" "2.9.1" 197 | "@parcel/utils" "2.9.1" 198 | "@parcel/workers" "2.9.1" 199 | abortcontroller-polyfill "^1.1.9" 200 | base-x "^3.0.8" 201 | browserslist "^4.6.6" 202 | clone "^2.1.1" 203 | dotenv "^7.0.0" 204 | dotenv-expand "^5.1.0" 205 | json5 "^2.2.0" 206 | msgpackr "^1.5.4" 207 | nullthrows "^1.1.1" 208 | semver "^5.7.1" 209 | 210 | "@parcel/diagnostic@2.9.1": 211 | version "2.9.1" 212 | resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.9.1.tgz#8fe5bdba1accb2b72151976fb66b65e9ef4418af" 213 | integrity sha512-LM+w4maoAsjcL+javaHw9B9oEQoLdg/fMCNbuTmAKpQWi16hfNkr4+xz7AxxwL3dCcL7uuvVgoUOUubwxWNLAA== 214 | dependencies: 215 | "@mischnic/json-sourcemap" "^0.1.0" 216 | nullthrows "^1.1.1" 217 | 218 | "@parcel/events@2.9.1": 219 | version "2.9.1" 220 | resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.9.1.tgz#8aa2a4477a8dbc679bafbca45dced63cdf58ed34" 221 | integrity sha512-tga4FiJB1TC4iOKBK66e9zXpcDFXvJhXmsgOMsgSTM6uCZMXeGaYEixHNlPDs3HTfg17qAmHHlhfgPBbku/aOg== 222 | 223 | "@parcel/fs-search@2.9.1": 224 | version "2.9.1" 225 | resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.9.1.tgz#e8e2a839f23a34d74971036b50553346f1cb6ce1" 226 | integrity sha512-F7SkVsMb5XYcWmeptLz5D3g76Raed3dmNulJMrWIECP8lJ1LUcCExQId7NsdeCfRbNRwaf84gdsjc/1GKM/QYg== 227 | 228 | "@parcel/fs@2.9.1": 229 | version "2.9.1" 230 | resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.9.1.tgz#8bcf0a9b6728abc12392a2831b8d87d9537126db" 231 | integrity sha512-F/GRHtHN4AuTauadsq/UQ1OSpLBLAS/96Sv1x09/AKZxNlZ2UzWExoYEhSkVM5smKVzSnx8XP9OqABcHcZwOLQ== 232 | dependencies: 233 | "@parcel/fs-search" "2.9.1" 234 | "@parcel/types" "2.9.1" 235 | "@parcel/utils" "2.9.1" 236 | "@parcel/watcher" "^2.0.7" 237 | "@parcel/workers" "2.9.1" 238 | 239 | "@parcel/graph@2.9.1": 240 | version "2.9.1" 241 | resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.9.1.tgz#d520de0ff8fadf8e973d36aaa91b6123b53cb4b2" 242 | integrity sha512-fc/Yk1XPzo3ZHhKS7l5aETAEBpnF0nK+0TawkNrQ2rcL21MG1kHNYSR8uBwOqyXmBSMEItals5Ixgd8fWa+9PQ== 243 | dependencies: 244 | nullthrows "^1.1.1" 245 | 246 | "@parcel/hash@2.9.1": 247 | version "2.9.1" 248 | resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.9.1.tgz#6654bc83cc3692f2872b168d47e6762a29e8988b" 249 | integrity sha512-fiqAIi/23h5tnH5W7DRTwOhfRPhadHvI7hYoG8YFGvnFxSQ/XCnOID0B0/vNhaluICSPeFcedjAmDVdqY6/X7w== 250 | dependencies: 251 | xxhash-wasm "^0.4.2" 252 | 253 | "@parcel/logger@2.9.1": 254 | version "2.9.1" 255 | resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.9.1.tgz#445f266780d0000d87626b390bb94b0cf096ed55" 256 | integrity sha512-wUH9ShrRr3RwNa75ymegDIAdJiY3dGB7HCgIP6VOOc2CGyGA2DJKbbYGfw5mkl3DV8lUV+dYsWYMGXZhInAQCQ== 257 | dependencies: 258 | "@parcel/diagnostic" "2.9.1" 259 | "@parcel/events" "2.9.1" 260 | 261 | "@parcel/markdown-ansi@2.9.1": 262 | version "2.9.1" 263 | resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.9.1.tgz#b5fe0a5bdb951748fc77f3fd3896c69511d8d03d" 264 | integrity sha512-FpOz2ltnKnm6QaQCdcpuAEwGuScVUq0ixT/QAmU7A3/cwlsoxqMkB2XeWYIVTjs7p7Bsu0Ctdid/6pdtP7ghpg== 265 | dependencies: 266 | chalk "^4.1.0" 267 | 268 | "@parcel/namer-default@2.9.1": 269 | version "2.9.1" 270 | resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.9.1.tgz#b93eb761c5bddb48893812d1aa8bf90f6ad5de3d" 271 | integrity sha512-XHpAc5JLQchUqRrYqnUvinReR2nCyiD+DhIedMW5hURwlCPBlfcTVf6M5kSSpjzqRDVKezx3TFF6dzZNv0fBJQ== 272 | dependencies: 273 | "@parcel/diagnostic" "2.9.1" 274 | "@parcel/plugin" "2.9.1" 275 | nullthrows "^1.1.1" 276 | 277 | "@parcel/node-resolver-core@3.0.1": 278 | version "3.0.1" 279 | resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-3.0.1.tgz#2a25ffdcefb01bc7537d5ab29886109a5ba7ecb7" 280 | integrity sha512-4owokOoHCONeazQGndB4PkIaUhZfyWuCT7Sx4UJc2UhR1V82MlahHrT2ItT0pkQyKWwCSNgHdBgdKUgKRdIiAw== 281 | dependencies: 282 | "@mischnic/json-sourcemap" "^0.1.0" 283 | "@parcel/diagnostic" "2.9.1" 284 | "@parcel/fs" "2.9.1" 285 | "@parcel/utils" "2.9.1" 286 | nullthrows "^1.1.1" 287 | semver "^5.7.1" 288 | 289 | "@parcel/optimizer-css@2.9.1": 290 | version "2.9.1" 291 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.9.1.tgz#5a9c0ddb95281dee139be620f03307678d828247" 292 | integrity sha512-IYQpV0kc0KN/aqRAWQsZ8b2pbI4ha4T5HAi27lTGIhQNvEixUtf0gJvCJVSlBxpdMiXVJq9pp97UamoNuB6oig== 293 | dependencies: 294 | "@parcel/diagnostic" "2.9.1" 295 | "@parcel/plugin" "2.9.1" 296 | "@parcel/source-map" "^2.1.1" 297 | "@parcel/utils" "2.9.1" 298 | browserslist "^4.6.6" 299 | lightningcss "^1.16.1" 300 | nullthrows "^1.1.1" 301 | 302 | "@parcel/optimizer-htmlnano@2.9.1": 303 | version "2.9.1" 304 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.1.tgz#2d767cfd975da7686d4eb68603555566b47d022f" 305 | integrity sha512-t/e9XsoXZViqOFWcz3LlEClCOYNCjP6MIo+p+WmAuc5+QFF0/9viNqgRbhVe8V1tbtRofxsm4BossFOjOBSjmg== 306 | dependencies: 307 | "@parcel/plugin" "2.9.1" 308 | htmlnano "^2.0.0" 309 | nullthrows "^1.1.1" 310 | posthtml "^0.16.5" 311 | svgo "^2.4.0" 312 | 313 | "@parcel/optimizer-image@2.9.1": 314 | version "2.9.1" 315 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.9.1.tgz#c9d5fe1d3c117526847f67f705fd3837b2b77578" 316 | integrity sha512-Ml51RUGbQXyoHZ9yhyal8J/khZeWZX5J8NPOEvkCmmOkxo/qM4CMPIvJStzzn5K7mOPRKUheDkM/QoNGO5gTwA== 317 | dependencies: 318 | "@parcel/diagnostic" "2.9.1" 319 | "@parcel/plugin" "2.9.1" 320 | "@parcel/utils" "2.9.1" 321 | "@parcel/workers" "2.9.1" 322 | 323 | "@parcel/optimizer-svgo@2.9.1": 324 | version "2.9.1" 325 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.1.tgz#71d59e843bcd98ea211070975b241127ab7641c8" 326 | integrity sha512-8XHSEIjJfdTFtUQzRiy0K+fbvdcheYc+azdyuJPnIV5AX04k4heKwp7uH328Ylk2k0JkfDyQmjFEyPj9qWDadQ== 327 | dependencies: 328 | "@parcel/diagnostic" "2.9.1" 329 | "@parcel/plugin" "2.9.1" 330 | "@parcel/utils" "2.9.1" 331 | svgo "^2.4.0" 332 | 333 | "@parcel/optimizer-swc@2.9.1": 334 | version "2.9.1" 335 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-swc/-/optimizer-swc-2.9.1.tgz#4531b547ef37d2e279b53916942463bc5d9fb7e6" 336 | integrity sha512-bLDkAwkmFE8YZNHcfJNj22haSLXrqjZkGXbPgGDkanCUS52yWv1+OFZ+6frX2q4EdXaTX8nFZSJL4VPHZZiUGQ== 337 | dependencies: 338 | "@parcel/diagnostic" "2.9.1" 339 | "@parcel/plugin" "2.9.1" 340 | "@parcel/source-map" "^2.1.1" 341 | "@parcel/utils" "2.9.1" 342 | "@swc/core" "^1.3.36" 343 | nullthrows "^1.1.1" 344 | 345 | "@parcel/package-manager@2.9.1": 346 | version "2.9.1" 347 | resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.9.1.tgz#3eed15d33489ef5f3089d11384916789275d6739" 348 | integrity sha512-cTUBUPRm62770Vw4YG5WGlkFxJII320nSobbP0TMggE/CGXg3ru2pvvX6WqXTFAHeM/z78xTPDq0NP97DBp5Ow== 349 | dependencies: 350 | "@parcel/diagnostic" "2.9.1" 351 | "@parcel/fs" "2.9.1" 352 | "@parcel/logger" "2.9.1" 353 | "@parcel/node-resolver-core" "3.0.1" 354 | "@parcel/types" "2.9.1" 355 | "@parcel/utils" "2.9.1" 356 | "@parcel/workers" "2.9.1" 357 | semver "^5.7.1" 358 | 359 | "@parcel/packager-css@2.9.1": 360 | version "2.9.1" 361 | resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.9.1.tgz#d070906edc2f565f1d042424deff5ff8210f7639" 362 | integrity sha512-efMShrIwVBY9twZTGQ5QFwl9H3xJg8nSjl/xgOGq9rrbkmcrVlfSgPL9ExNx75EvmOwOKxZjFiMsNYNICPNfgg== 363 | dependencies: 364 | "@parcel/diagnostic" "2.9.1" 365 | "@parcel/plugin" "2.9.1" 366 | "@parcel/source-map" "^2.1.1" 367 | "@parcel/utils" "2.9.1" 368 | nullthrows "^1.1.1" 369 | 370 | "@parcel/packager-html@2.9.1": 371 | version "2.9.1" 372 | resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.9.1.tgz#67ec088a5f54906076d91bd1021c053727d883ea" 373 | integrity sha512-mP7iIwyFDZ21XwD2SlwZoSrvKpS5Amlpi/ywd0dLdwQb5TL+Q2f05IcRNfFbWdVd1AJycDQ85ERokNKN3QPMkg== 374 | dependencies: 375 | "@parcel/plugin" "2.9.1" 376 | "@parcel/types" "2.9.1" 377 | "@parcel/utils" "2.9.1" 378 | nullthrows "^1.1.1" 379 | posthtml "^0.16.5" 380 | 381 | "@parcel/packager-js@2.9.1": 382 | version "2.9.1" 383 | resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.9.1.tgz#c18cbd718f69cef1868dabfa9547d0dbb159f169" 384 | integrity sha512-MmeKdp/obO36M8Y9yYAFiFkdhRFbQtYGSxbMwm2JVtRKMcFmlR5KzqLUg67OX6qgKw5lZZ1TkYhSI0hQQ6+Vqw== 385 | dependencies: 386 | "@parcel/diagnostic" "2.9.1" 387 | "@parcel/hash" "2.9.1" 388 | "@parcel/plugin" "2.9.1" 389 | "@parcel/source-map" "^2.1.1" 390 | "@parcel/utils" "2.9.1" 391 | globals "^13.2.0" 392 | nullthrows "^1.1.1" 393 | 394 | "@parcel/packager-raw-url@2.9.1": 395 | version "2.9.1" 396 | resolved "https://registry.yarnpkg.com/@parcel/packager-raw-url/-/packager-raw-url-2.9.1.tgz#932dc1a678974ebae75656960cc3c4d4b418f24d" 397 | integrity sha512-sS9a9CsYaWtfqaRLLGceRhSVeytC5+4PR1ZrXG+5/wM5kRhBs8kj/jsCmbcc7QXaH7pMAAhg0ahMqX9zf1jXGQ== 398 | dependencies: 399 | "@parcel/plugin" "2.9.1" 400 | "@parcel/utils" "2.9.1" 401 | 402 | "@parcel/packager-raw@2.9.1": 403 | version "2.9.1" 404 | resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.9.1.tgz#bba90032196d0e7b9730d9029f38fa2e3f998a67" 405 | integrity sha512-qHJ389R5cLgR2PcJt8sOrNBcAY0qpZRMTOMgkc9zYkKy1tdUMgCUuDfO1kShfv4E7rr084mtlu9tK8MXChyF6w== 406 | dependencies: 407 | "@parcel/plugin" "2.9.1" 408 | 409 | "@parcel/packager-svg@2.9.1": 410 | version "2.9.1" 411 | resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.9.1.tgz#6adaeefd3687b0da5641f0d1a1f0bd99483fffaf" 412 | integrity sha512-aRzuiwcUlNATfSIbeYpDkJXvwdiAAbiQlxSz6cI53NqWwZn+Dn79WyiKPBST14ij4/P3ZjkcwXevqHpvXP/ArQ== 413 | dependencies: 414 | "@parcel/plugin" "2.9.1" 415 | "@parcel/types" "2.9.1" 416 | "@parcel/utils" "2.9.1" 417 | posthtml "^0.16.4" 418 | 419 | "@parcel/plugin@2.9.1": 420 | version "2.9.1" 421 | resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.9.1.tgz#9ce68ebe2e568606d8b61b1f3540c2747cf91bee" 422 | integrity sha512-kD+BNkPGRcxZZUKhAXqF/bilUMhXUlf/ZixVlBS5rEsUB1yx/Ze8c4ypaKr5WsEwv34C+X4p4WFYdZVJEr3Y+g== 423 | dependencies: 424 | "@parcel/types" "2.9.1" 425 | 426 | "@parcel/profiler@2.9.1": 427 | version "2.9.1" 428 | resolved "https://registry.yarnpkg.com/@parcel/profiler/-/profiler-2.9.1.tgz#12a8928a2f15356b42cdfe2939083e3e15aba5f7" 429 | integrity sha512-hrptwbh9uUxnWHAAXiZ6BtpM74cU+VfrOWgnmUA8pkYWBmrb2wSLeqRKl8FiSt+nfRTTbNAIlmn9vk2x+wRNOA== 430 | dependencies: 431 | "@parcel/diagnostic" "2.9.1" 432 | "@parcel/events" "2.9.1" 433 | chrome-trace-event "^1.0.2" 434 | 435 | "@parcel/reporter-cli@2.9.1": 436 | version "2.9.1" 437 | resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.9.1.tgz#a5133127dc13f443aa119f5c6b531f2741fa9f54" 438 | integrity sha512-xzJaaHQwcsmHijlCl7gOAdqU0n6AnW7c7rN8AXDH8BvnOx2v8NC8nCIEmDTOfpQYepcuER2+ilTQ7jpDx/iDhg== 439 | dependencies: 440 | "@parcel/plugin" "2.9.1" 441 | "@parcel/types" "2.9.1" 442 | "@parcel/utils" "2.9.1" 443 | chalk "^4.1.0" 444 | term-size "^2.2.1" 445 | 446 | "@parcel/reporter-dev-server@2.9.1": 447 | version "2.9.1" 448 | resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.1.tgz#ebbf1558e8c4f90906d90ddbe431892ebfc86601" 449 | integrity sha512-Wa9kmtnuYTqEsKakhrSLvZmWxM4TB+Dg2jl1vC3gYfvlsgt/d/Hp/y2giPH1EeCm4wEEQfdAY3WmSUx9p1x07w== 450 | dependencies: 451 | "@parcel/plugin" "2.9.1" 452 | "@parcel/utils" "2.9.1" 453 | 454 | "@parcel/reporter-tracer@2.9.1": 455 | version "2.9.1" 456 | resolved "https://registry.yarnpkg.com/@parcel/reporter-tracer/-/reporter-tracer-2.9.1.tgz#aef67c36b2f5c58ace1122920fb28d3ef2db9a12" 457 | integrity sha512-LgZKx9qwBAChWHBcpHW8GJXz45IGtiPmzs6HIDavZOiGqjGVzmbHUKxHnFaRZqR6WznJ+0ay/2o+BrJ8cyXUcg== 458 | dependencies: 459 | "@parcel/plugin" "2.9.1" 460 | "@parcel/utils" "2.9.1" 461 | chrome-trace-event "^1.0.3" 462 | nullthrows "^1.1.1" 463 | 464 | "@parcel/resolver-default@2.9.1": 465 | version "2.9.1" 466 | resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.9.1.tgz#c28621b9ba7cd06959a5039eb4b475880cc85228" 467 | integrity sha512-Q+knNaRDTbGIGqUnddtWEgpYduVBkDyi/CpxKpi7dP7sVYNJsXwEf82hpjX6/XqotA5dehT63yJkvJ/wxJF1Nw== 468 | dependencies: 469 | "@parcel/node-resolver-core" "3.0.1" 470 | "@parcel/plugin" "2.9.1" 471 | 472 | "@parcel/runtime-browser-hmr@2.9.1": 473 | version "2.9.1" 474 | resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.1.tgz#663d706cf227914a2ca0c07b9ef8c7e2e3253840" 475 | integrity sha512-C+023FOsrycpBHUgUf7Nv4uN0NrLN3UkeymsAHQlgZD5QQD7+nhG6p9PQ7+HbbEAaGaeO7c/86s2qRUglufNig== 476 | dependencies: 477 | "@parcel/plugin" "2.9.1" 478 | "@parcel/utils" "2.9.1" 479 | 480 | "@parcel/runtime-js@2.9.1": 481 | version "2.9.1" 482 | resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.9.1.tgz#8cdc0fe7e0e6b08ffe2c3fd0ea813de73c48bdb0" 483 | integrity sha512-caT1s1BqYNFGFAz9ul7uwDf+ZXzipiYYoHphhmT2JFweQmRA1CrMeFCuCQa2exsdu+UQpRbuKd+v5UUS2n0poQ== 484 | dependencies: 485 | "@parcel/diagnostic" "2.9.1" 486 | "@parcel/plugin" "2.9.1" 487 | "@parcel/utils" "2.9.1" 488 | nullthrows "^1.1.1" 489 | 490 | "@parcel/runtime-react-refresh@2.9.1": 491 | version "2.9.1" 492 | resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.1.tgz#0e2f0aaf60f3ded371a4babc3ef37ac7473720c0" 493 | integrity sha512-opDW9p3f4gVc1aVdFAyLWTL+2S8rhsPdBQRBHEi4WE2DRe/9lpA12NN5KUUHy88dlIr3wyzmaO2Fts0r/x80zg== 494 | dependencies: 495 | "@parcel/plugin" "2.9.1" 496 | "@parcel/utils" "2.9.1" 497 | react-error-overlay "6.0.9" 498 | react-refresh "^0.9.0" 499 | 500 | "@parcel/runtime-service-worker@2.9.1": 501 | version "2.9.1" 502 | resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.1.tgz#4e4fd68bcda49afd20f31cf4c0fc410e539baacf" 503 | integrity sha512-TED4MouYjP7xbU9V7/3rjnmuWbCefrP+OC+eQJG6j3HwKiL92QTZ6trWqdLuxFhtZMXKjwbWaBBbIcELB/PbtQ== 504 | dependencies: 505 | "@parcel/plugin" "2.9.1" 506 | "@parcel/utils" "2.9.1" 507 | nullthrows "^1.1.1" 508 | 509 | "@parcel/service-worker@^2.9.1": 510 | version "2.9.1" 511 | resolved "https://registry.yarnpkg.com/@parcel/service-worker/-/service-worker-2.9.1.tgz#445345ca7e0068b9eb0f528bc902ad32ce8aa208" 512 | integrity sha512-T6wvt30cN4wK3kRx7jNOno7mXfj3Bl+4QlQ3l/NHUKeumDzyb8RNdAJD71NmxEY0R4yJ+zCMDd3WZa8KXqyrsQ== 513 | 514 | "@parcel/source-map@^2.1.1": 515 | version "2.1.1" 516 | resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.1.tgz#fb193b82dba6dd62cc7a76b326f57bb35000a782" 517 | integrity sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew== 518 | dependencies: 519 | detect-libc "^1.0.3" 520 | 521 | "@parcel/transformer-babel@2.9.1": 522 | version "2.9.1" 523 | resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.9.1.tgz#db7c11e14b33ce6ce84170eebf93c3fa5a96ae3a" 524 | integrity sha512-HEU3bavD9Cu0RP5T1ioGLbsOQDqND/SQWal8L2f9HsgwTs2kzmTxYylNccqNjAMj3NnoyXzKMKbZyG8qEuLlpw== 525 | dependencies: 526 | "@parcel/diagnostic" "2.9.1" 527 | "@parcel/plugin" "2.9.1" 528 | "@parcel/source-map" "^2.1.1" 529 | "@parcel/utils" "2.9.1" 530 | browserslist "^4.6.6" 531 | json5 "^2.2.0" 532 | nullthrows "^1.1.1" 533 | semver "^5.7.0" 534 | 535 | "@parcel/transformer-css@2.9.1": 536 | version "2.9.1" 537 | resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.9.1.tgz#c70fceddb5352e3fc8a121842c04138a57ec311f" 538 | integrity sha512-nT+xOfyveX6qSb088dOh59HWJ1gm7DAIQZPbjTa1wLzRQul8ysdQRf/loulBmtUheol7YwQtVvUHN2XgoMDCAw== 539 | dependencies: 540 | "@parcel/diagnostic" "2.9.1" 541 | "@parcel/plugin" "2.9.1" 542 | "@parcel/source-map" "^2.1.1" 543 | "@parcel/utils" "2.9.1" 544 | browserslist "^4.6.6" 545 | lightningcss "^1.16.1" 546 | nullthrows "^1.1.1" 547 | 548 | "@parcel/transformer-html@2.9.1": 549 | version "2.9.1" 550 | resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.9.1.tgz#306754b6448df1ef8c3bf0af9eacf6ab019d48df" 551 | integrity sha512-pIkJbcB91Dl2RyZmVd9neGkf7XJeYXwgx0et5hktw+3m0S2QB399OjVWwi5Q6ZdtTrWkQnHLmbeHT3NOmNWlaw== 552 | dependencies: 553 | "@parcel/diagnostic" "2.9.1" 554 | "@parcel/hash" "2.9.1" 555 | "@parcel/plugin" "2.9.1" 556 | nullthrows "^1.1.1" 557 | posthtml "^0.16.5" 558 | posthtml-parser "^0.10.1" 559 | posthtml-render "^3.0.0" 560 | semver "^5.7.1" 561 | srcset "4" 562 | 563 | "@parcel/transformer-image@2.9.1": 564 | version "2.9.1" 565 | resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.9.1.tgz#efbc289114c9330f85a4307b3c7e6e31ec13808d" 566 | integrity sha512-3D4zEavCM1i354ZgJWg7RBNgASA7Q2iHN374lH5hT6I7VAJzNT+PTNrPNQ4vKhi69r+i1sQQzsPdgEUXOExmbQ== 567 | dependencies: 568 | "@parcel/plugin" "2.9.1" 569 | "@parcel/utils" "2.9.1" 570 | "@parcel/workers" "2.9.1" 571 | nullthrows "^1.1.1" 572 | 573 | "@parcel/transformer-js@2.9.1": 574 | version "2.9.1" 575 | resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.9.1.tgz#175e552de1b4466b5d4ae6f51b6c58d7a7d6a549" 576 | integrity sha512-7hlbAIufIvx6iPspfZ3v1g2cmtpaNEaC04RzRv8HVVru8TE868yplFI840ZBnF5ylOfmxwFTUjlphVtVcPs13A== 577 | dependencies: 578 | "@parcel/diagnostic" "2.9.1" 579 | "@parcel/plugin" "2.9.1" 580 | "@parcel/source-map" "^2.1.1" 581 | "@parcel/utils" "2.9.1" 582 | "@parcel/workers" "2.9.1" 583 | "@swc/helpers" "^0.5.0" 584 | browserslist "^4.6.6" 585 | nullthrows "^1.1.1" 586 | regenerator-runtime "^0.13.7" 587 | semver "^5.7.1" 588 | 589 | "@parcel/transformer-json@2.9.1": 590 | version "2.9.1" 591 | resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.9.1.tgz#bb754e02d7f13cc6becfe473857823bf435087e6" 592 | integrity sha512-yFRSz1qVbdCssC65D37Ru3diQk7GQl5ZOOyQ7MeMYlhvl8mcFKGRC3wUAyqBZrh70VOWuWR7WS2XLdqTdE9WqQ== 593 | dependencies: 594 | "@parcel/plugin" "2.9.1" 595 | json5 "^2.2.0" 596 | 597 | "@parcel/transformer-postcss@2.9.1": 598 | version "2.9.1" 599 | resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.9.1.tgz#5cccedb2bf2f14afc91a42b354d219cf47f42ee5" 600 | integrity sha512-sNSJbdT4Z8H+/cZ/vCmos44SfbB9O5gNgMEgGa6WqU7MV7cVlnE8zuNJkxR97ZZTpIXNrfVerOY3lOrUrFCxdA== 601 | dependencies: 602 | "@parcel/diagnostic" "2.9.1" 603 | "@parcel/hash" "2.9.1" 604 | "@parcel/plugin" "2.9.1" 605 | "@parcel/utils" "2.9.1" 606 | clone "^2.1.1" 607 | nullthrows "^1.1.1" 608 | postcss-value-parser "^4.2.0" 609 | semver "^5.7.1" 610 | 611 | "@parcel/transformer-posthtml@2.9.1": 612 | version "2.9.1" 613 | resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.1.tgz#b999b3366c73202ae28a1f7cb7a05b80ec0b766b" 614 | integrity sha512-I6fr6lVAqjDxdkOwxelx7FibMWP55JPf3ZTXKCWpoIGkOuT2i2tYZMdXEHVshZWJmByelbYSC96w8P8rSY+6XQ== 615 | dependencies: 616 | "@parcel/plugin" "2.9.1" 617 | "@parcel/utils" "2.9.1" 618 | nullthrows "^1.1.1" 619 | posthtml "^0.16.5" 620 | posthtml-parser "^0.10.1" 621 | posthtml-render "^3.0.0" 622 | semver "^5.7.1" 623 | 624 | "@parcel/transformer-raw@2.9.1": 625 | version "2.9.1" 626 | resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.9.1.tgz#7a329ae7d8eb42d9f424daa209d99edfd302b6fa" 627 | integrity sha512-Wr0Y9fETiyF5ntL3yhn/ZXjcnswcn1T9YLXa+yAxpAxKW+/D7A1jKVS0tyDOZsdakWA9gzlLP6w1O4Nl8pVmEg== 628 | dependencies: 629 | "@parcel/plugin" "2.9.1" 630 | 631 | "@parcel/transformer-react-refresh-wrap@2.9.1": 632 | version "2.9.1" 633 | resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.1.tgz#6600352f0d83fab99f0c9cb99d048028c649c614" 634 | integrity sha512-ML+KDvLoZ6O+9r3/yf8DeVtobhYc9DPXYHZ75aXoFyou97I9WDf4EqlY4/MSkbZV79FUXxC68dyLJj3Q9ILqeA== 635 | dependencies: 636 | "@parcel/plugin" "2.9.1" 637 | "@parcel/utils" "2.9.1" 638 | react-refresh "^0.9.0" 639 | 640 | "@parcel/transformer-svg@2.9.1": 641 | version "2.9.1" 642 | resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.9.1.tgz#c267e15c6fa1517684db1ca335ccded6a3a7dfdd" 643 | integrity sha512-DYcUfutjtghPXMVybFygncIKJl/4rrpQMxv8yTVeDtplUTvFzbI+3hIoYfYm8z9CXaSBzsCw2Kud6PD8Ob2AzQ== 644 | dependencies: 645 | "@parcel/diagnostic" "2.9.1" 646 | "@parcel/hash" "2.9.1" 647 | "@parcel/plugin" "2.9.1" 648 | nullthrows "^1.1.1" 649 | posthtml "^0.16.5" 650 | posthtml-parser "^0.10.1" 651 | posthtml-render "^3.0.0" 652 | semver "^5.7.1" 653 | 654 | "@parcel/transformer-webmanifest@2.9.1": 655 | version "2.9.1" 656 | resolved "https://registry.yarnpkg.com/@parcel/transformer-webmanifest/-/transformer-webmanifest-2.9.1.tgz#23f03bdda7760d1f031d1e556e869b82d792f15c" 657 | integrity sha512-mnNfDJQBaqkc8S0I9IOHEM0dKRMXNMXcl4vUMCUrcAiNYGcSLaPrSfZqvyuUgc5Lx6T2FCeQ/KzamWBdH3e0PA== 658 | dependencies: 659 | "@mischnic/json-sourcemap" "^0.1.0" 660 | "@parcel/diagnostic" "2.9.1" 661 | "@parcel/plugin" "2.9.1" 662 | "@parcel/utils" "2.9.1" 663 | 664 | "@parcel/types@2.9.1": 665 | version "2.9.1" 666 | resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.9.1.tgz#6d79b5b6459119e58aac734adf2c3c4a261b983f" 667 | integrity sha512-LBx4Tvr1sK9t+FmPjS4jPvcmUcJo6co22sn0pBuz2oXISs/YK2N+3ZHXL+KsozKvLn2wXysgaWFIARN9xFoORw== 668 | dependencies: 669 | "@parcel/cache" "2.9.1" 670 | "@parcel/diagnostic" "2.9.1" 671 | "@parcel/fs" "2.9.1" 672 | "@parcel/package-manager" "2.9.1" 673 | "@parcel/source-map" "^2.1.1" 674 | "@parcel/workers" "2.9.1" 675 | utility-types "^3.10.0" 676 | 677 | "@parcel/utils@2.9.1": 678 | version "2.9.1" 679 | resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.9.1.tgz#2ecec9b17ce880b1768c2956545e18af3e63b791" 680 | integrity sha512-0P/zIvtvLyuzQA4VFMzA8F22lrUyGR+phve/NlBUH+4Tn+Rt/evh9fP9vG1YTVMXWd90tesLdrtqatm1hqrJSA== 681 | dependencies: 682 | "@parcel/codeframe" "2.9.1" 683 | "@parcel/diagnostic" "2.9.1" 684 | "@parcel/hash" "2.9.1" 685 | "@parcel/logger" "2.9.1" 686 | "@parcel/markdown-ansi" "2.9.1" 687 | "@parcel/source-map" "^2.1.1" 688 | chalk "^4.1.0" 689 | nullthrows "^1.1.1" 690 | 691 | "@parcel/watcher@^2.0.7": 692 | version "2.1.0" 693 | resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.1.0.tgz#5f32969362db4893922c526a842d8af7a8538545" 694 | integrity sha512-8s8yYjd19pDSsBpbkOHnT6Z2+UJSuLQx61pCFM0s5wSRvKCEMDjd/cHY3/GI1szHIWbpXpsJdg3V6ISGGx9xDw== 695 | dependencies: 696 | is-glob "^4.0.3" 697 | micromatch "^4.0.5" 698 | node-addon-api "^3.2.1" 699 | node-gyp-build "^4.3.0" 700 | 701 | "@parcel/workers@2.9.1": 702 | version "2.9.1" 703 | resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.9.1.tgz#a6962f0b8a53d59ebb4de21ce5e8f49b12bf69ce" 704 | integrity sha512-24R4IRMX8TBghak6pDCzM5B8NB4LTt0pI4dwNqSENyZA/Q5s/xMbG5gdn4aTwkAyIQ5lHrgDsHzoHbjOT0HLYQ== 705 | dependencies: 706 | "@parcel/diagnostic" "2.9.1" 707 | "@parcel/logger" "2.9.1" 708 | "@parcel/profiler" "2.9.1" 709 | "@parcel/types" "2.9.1" 710 | "@parcel/utils" "2.9.1" 711 | nullthrows "^1.1.1" 712 | 713 | "@swc/core-darwin-arm64@1.3.62": 714 | version "1.3.62" 715 | resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz#dafb50bf784c6b7b40dce6d8cf0605f6729812cb" 716 | integrity sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA== 717 | 718 | "@swc/core-darwin-x64@1.3.62": 719 | version "1.3.62" 720 | resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz#324bd144268860338040db64c42c2345fcaaebcf" 721 | integrity sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ== 722 | 723 | "@swc/core-linux-arm-gnueabihf@1.3.62": 724 | version "1.3.62" 725 | resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz#9b5ca188ea3c91827e43e4287bd20ce2a7cb7d81" 726 | integrity sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ== 727 | 728 | "@swc/core-linux-arm64-gnu@1.3.62": 729 | version "1.3.62" 730 | resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz#b208b005223fd9c4c4a12fc0e24070c5e902965f" 731 | integrity sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw== 732 | 733 | "@swc/core-linux-arm64-musl@1.3.62": 734 | version "1.3.62" 735 | resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz#bf66add093fa732d3b7f629e00b6ef9bf3c483f2" 736 | integrity sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg== 737 | 738 | "@swc/core-linux-x64-gnu@1.3.62": 739 | version "1.3.62" 740 | resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz#b97eee374986388b71d87c67d7edb8208356dde2" 741 | integrity sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A== 742 | 743 | "@swc/core-linux-x64-musl@1.3.62": 744 | version "1.3.62" 745 | resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz#548ccdef6d7535ee7fea6ec9488322411f10da1a" 746 | integrity sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg== 747 | 748 | "@swc/core-win32-arm64-msvc@1.3.62": 749 | version "1.3.62" 750 | resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz#fc0ca735b23c017fe8ff6f85aa4788ddd1ac583d" 751 | integrity sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w== 752 | 753 | "@swc/core-win32-ia32-msvc@1.3.62": 754 | version "1.3.62" 755 | resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz#f8dfbb4f0763d2db5ef420b04da3b5cb73897756" 756 | integrity sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw== 757 | 758 | "@swc/core-win32-x64-msvc@1.3.62": 759 | version "1.3.62" 760 | resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz#e661ec99c5ac91f1cd63c02b5f114f73f55e7b15" 761 | integrity sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ== 762 | 763 | "@swc/core@^1.3.36": 764 | version "1.3.62" 765 | resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.62.tgz#bc93ede0981ee69fe17d753e1d693ce3afa6c16b" 766 | integrity sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ== 767 | optionalDependencies: 768 | "@swc/core-darwin-arm64" "1.3.62" 769 | "@swc/core-darwin-x64" "1.3.62" 770 | "@swc/core-linux-arm-gnueabihf" "1.3.62" 771 | "@swc/core-linux-arm64-gnu" "1.3.62" 772 | "@swc/core-linux-arm64-musl" "1.3.62" 773 | "@swc/core-linux-x64-gnu" "1.3.62" 774 | "@swc/core-linux-x64-musl" "1.3.62" 775 | "@swc/core-win32-arm64-msvc" "1.3.62" 776 | "@swc/core-win32-ia32-msvc" "1.3.62" 777 | "@swc/core-win32-x64-msvc" "1.3.62" 778 | 779 | "@swc/helpers@^0.5.0": 780 | version "0.5.1" 781 | resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.1.tgz#e9031491aa3f26bfcc974a67f48bd456c8a5357a" 782 | integrity sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg== 783 | dependencies: 784 | tslib "^2.4.0" 785 | 786 | "@trysound/sax@0.2.0": 787 | version "0.2.0" 788 | resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" 789 | integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== 790 | 791 | "@types/mithril@^2.0.12": 792 | version "2.0.12" 793 | resolved "https://registry.yarnpkg.com/@types/mithril/-/mithril-2.0.12.tgz#3391c691617c79e2e8e60dfa97527fc948cf07db" 794 | integrity sha512-vedzt04n3EB7rcnfSLCv3+w3qJLkGWdsNRBKvelTqhSJSfg73Roq9b+rcnn9zeqGYtQAMqNcO6vNBR/w0OzipQ== 795 | 796 | "@types/parse-json@^4.0.0": 797 | version "4.0.0" 798 | resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" 799 | integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== 800 | 801 | abortcontroller-polyfill@^1.1.9: 802 | version "1.7.3" 803 | resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz#1b5b487bd6436b5b764fd52a612509702c3144b5" 804 | integrity sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q== 805 | 806 | ansi-styles@^3.2.1: 807 | version "3.2.1" 808 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 809 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 810 | dependencies: 811 | color-convert "^1.9.0" 812 | 813 | ansi-styles@^4.1.0: 814 | version "4.3.0" 815 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 816 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 817 | dependencies: 818 | color-convert "^2.0.1" 819 | 820 | balanced-match@^1.0.0: 821 | version "1.0.2" 822 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 823 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 824 | 825 | base-x@^3.0.8: 826 | version "3.0.9" 827 | resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" 828 | integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== 829 | dependencies: 830 | safe-buffer "^5.0.1" 831 | 832 | boolbase@^1.0.0: 833 | version "1.0.0" 834 | resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" 835 | integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= 836 | 837 | brace-expansion@^1.1.7: 838 | version "1.1.11" 839 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 840 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 841 | dependencies: 842 | balanced-match "^1.0.0" 843 | concat-map "0.0.1" 844 | 845 | braces@^3.0.2: 846 | version "3.0.2" 847 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 848 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 849 | dependencies: 850 | fill-range "^7.0.1" 851 | 852 | browserslist@^4.6.6: 853 | version "4.20.2" 854 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" 855 | integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== 856 | dependencies: 857 | caniuse-lite "^1.0.30001317" 858 | electron-to-chromium "^1.4.84" 859 | escalade "^3.1.1" 860 | node-releases "^2.0.2" 861 | picocolors "^1.0.0" 862 | 863 | callsites@^3.0.0: 864 | version "3.1.0" 865 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 866 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 867 | 868 | caniuse-lite@^1.0.30001317: 869 | version "1.0.30001322" 870 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz#2e4c09d11e1e8f852767dab287069a8d0c29d623" 871 | integrity sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew== 872 | 873 | chalk@^2.0.0: 874 | version "2.4.2" 875 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 876 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 877 | dependencies: 878 | ansi-styles "^3.2.1" 879 | escape-string-regexp "^1.0.5" 880 | supports-color "^5.3.0" 881 | 882 | chalk@^4.1.0: 883 | version "4.1.2" 884 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 885 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 886 | dependencies: 887 | ansi-styles "^4.1.0" 888 | supports-color "^7.1.0" 889 | 890 | chrome-trace-event@^1.0.2, chrome-trace-event@^1.0.3: 891 | version "1.0.3" 892 | resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" 893 | integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== 894 | 895 | clone@^2.1.1: 896 | version "2.1.2" 897 | resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" 898 | integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= 899 | 900 | color-convert@^1.9.0: 901 | version "1.9.3" 902 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 903 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 904 | dependencies: 905 | color-name "1.1.3" 906 | 907 | color-convert@^2.0.1: 908 | version "2.0.1" 909 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 910 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 911 | dependencies: 912 | color-name "~1.1.4" 913 | 914 | color-name@1.1.3: 915 | version "1.1.3" 916 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 917 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 918 | 919 | color-name@~1.1.4: 920 | version "1.1.4" 921 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 922 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 923 | 924 | commander@^7.0.0, commander@^7.2.0: 925 | version "7.2.0" 926 | resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" 927 | integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== 928 | 929 | concat-map@0.0.1: 930 | version "0.0.1" 931 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 932 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 933 | 934 | cosmiconfig@^7.0.1: 935 | version "7.0.1" 936 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" 937 | integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== 938 | dependencies: 939 | "@types/parse-json" "^4.0.0" 940 | import-fresh "^3.2.1" 941 | parse-json "^5.0.0" 942 | path-type "^4.0.0" 943 | yaml "^1.10.0" 944 | 945 | css-select@^4.1.3: 946 | version "4.3.0" 947 | resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" 948 | integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== 949 | dependencies: 950 | boolbase "^1.0.0" 951 | css-what "^6.0.1" 952 | domhandler "^4.3.1" 953 | domutils "^2.8.0" 954 | nth-check "^2.0.1" 955 | 956 | css-tree@^1.1.2, css-tree@^1.1.3: 957 | version "1.1.3" 958 | resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" 959 | integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== 960 | dependencies: 961 | mdn-data "2.0.14" 962 | source-map "^0.6.1" 963 | 964 | css-what@^6.0.1: 965 | version "6.0.1" 966 | resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.0.1.tgz#3be33be55b9f302f710ba3a9c3abc1e2a63fc7eb" 967 | integrity sha512-z93ZGFLNc6yaoXAmVhqoSIb+BduplteCt1fepvwhBUQK6MNE4g6fgjpuZKJKp0esUe+vXWlIkwZZjNWoOKw0ZA== 968 | 969 | csso@^4.2.0: 970 | version "4.2.0" 971 | resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" 972 | integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== 973 | dependencies: 974 | css-tree "^1.1.2" 975 | 976 | detect-libc@^1.0.3: 977 | version "1.0.3" 978 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 979 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= 980 | 981 | dom-serializer@^1.0.1: 982 | version "1.3.2" 983 | resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" 984 | integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== 985 | dependencies: 986 | domelementtype "^2.0.1" 987 | domhandler "^4.2.0" 988 | entities "^2.0.0" 989 | 990 | domelementtype@^2.0.1, domelementtype@^2.2.0: 991 | version "2.2.0" 992 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" 993 | integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== 994 | 995 | domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1: 996 | version "4.3.1" 997 | resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" 998 | integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== 999 | dependencies: 1000 | domelementtype "^2.2.0" 1001 | 1002 | domutils@^2.8.0: 1003 | version "2.8.0" 1004 | resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" 1005 | integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== 1006 | dependencies: 1007 | dom-serializer "^1.0.1" 1008 | domelementtype "^2.2.0" 1009 | domhandler "^4.2.0" 1010 | 1011 | dotenv-expand@^5.1.0: 1012 | version "5.1.0" 1013 | resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" 1014 | integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== 1015 | 1016 | dotenv@^7.0.0: 1017 | version "7.0.0" 1018 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" 1019 | integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== 1020 | 1021 | electron-to-chromium@^1.4.84: 1022 | version "1.4.100" 1023 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.100.tgz#da82de8a19a47ea3dcdf141dde85355942fbc4e7" 1024 | integrity sha512-pNrSE2naf8fizl6/Uxq8UbKb8hU9EiYW4OzCYswosXoLV5NTMOUVKECNzDaHiUubsPq/kAckOzZd7zd8S8CHVw== 1025 | 1026 | entities@^2.0.0: 1027 | version "2.2.0" 1028 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" 1029 | integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== 1030 | 1031 | entities@^3.0.1: 1032 | version "3.0.1" 1033 | resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" 1034 | integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== 1035 | 1036 | error-ex@^1.3.1: 1037 | version "1.3.2" 1038 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 1039 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 1040 | dependencies: 1041 | is-arrayish "^0.2.1" 1042 | 1043 | escalade@^3.1.1: 1044 | version "3.1.1" 1045 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 1046 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 1047 | 1048 | escape-string-regexp@^1.0.5: 1049 | version "1.0.5" 1050 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 1051 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 1052 | 1053 | fill-range@^7.0.1: 1054 | version "7.0.1" 1055 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 1056 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 1057 | dependencies: 1058 | to-regex-range "^5.0.1" 1059 | 1060 | fs.realpath@^1.0.0: 1061 | version "1.0.0" 1062 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 1063 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 1064 | 1065 | get-port@^4.2.0: 1066 | version "4.2.0" 1067 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" 1068 | integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== 1069 | 1070 | glob@^7.1.3: 1071 | version "7.2.3" 1072 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 1073 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 1074 | dependencies: 1075 | fs.realpath "^1.0.0" 1076 | inflight "^1.0.4" 1077 | inherits "2" 1078 | minimatch "^3.1.1" 1079 | once "^1.3.0" 1080 | path-is-absolute "^1.0.0" 1081 | 1082 | globals@^13.2.0: 1083 | version "13.13.0" 1084 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" 1085 | integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== 1086 | dependencies: 1087 | type-fest "^0.20.2" 1088 | 1089 | has-flag@^3.0.0: 1090 | version "3.0.0" 1091 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 1092 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 1093 | 1094 | has-flag@^4.0.0: 1095 | version "4.0.0" 1096 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 1097 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 1098 | 1099 | htmlnano@^2.0.0: 1100 | version "2.0.0" 1101 | resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.0.0.tgz#07376faa064f7e1e832dfd91e1a9f606b0bc9b78" 1102 | integrity sha512-thKQfhcp2xgtsWNE27A2bliEeqVL5xjAgGn0wajyttvFFsvFWWah1ntV9aEX61gz0T6MBQ5xK/1lXuEumhJTcg== 1103 | dependencies: 1104 | cosmiconfig "^7.0.1" 1105 | posthtml "^0.16.5" 1106 | timsort "^0.3.0" 1107 | 1108 | htmlparser2@^7.1.1: 1109 | version "7.2.0" 1110 | resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5" 1111 | integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog== 1112 | dependencies: 1113 | domelementtype "^2.0.1" 1114 | domhandler "^4.2.2" 1115 | domutils "^2.8.0" 1116 | entities "^3.0.1" 1117 | 1118 | import-fresh@^3.2.1: 1119 | version "3.3.0" 1120 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 1121 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 1122 | dependencies: 1123 | parent-module "^1.0.0" 1124 | resolve-from "^4.0.0" 1125 | 1126 | inflight@^1.0.4: 1127 | version "1.0.6" 1128 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 1129 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 1130 | dependencies: 1131 | once "^1.3.0" 1132 | wrappy "1" 1133 | 1134 | inherits@2: 1135 | version "2.0.4" 1136 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 1137 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 1138 | 1139 | is-arrayish@^0.2.1: 1140 | version "0.2.1" 1141 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 1142 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= 1143 | 1144 | is-extglob@^2.1.1: 1145 | version "2.1.1" 1146 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 1147 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 1148 | 1149 | is-glob@^4.0.3: 1150 | version "4.0.3" 1151 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 1152 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 1153 | dependencies: 1154 | is-extglob "^2.1.1" 1155 | 1156 | is-json@^2.0.1: 1157 | version "2.0.1" 1158 | resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff" 1159 | integrity sha1-a+Fm0USCihMdaGiRuYPfYsOUkf8= 1160 | 1161 | is-number@^7.0.0: 1162 | version "7.0.0" 1163 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 1164 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 1165 | 1166 | js-tokens@^4.0.0: 1167 | version "4.0.0" 1168 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 1169 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 1170 | 1171 | json-parse-even-better-errors@^2.3.0: 1172 | version "2.3.1" 1173 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" 1174 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== 1175 | 1176 | json5@^2.2.0, json5@^2.2.1: 1177 | version "2.2.1" 1178 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" 1179 | integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== 1180 | 1181 | lightningcss-darwin-arm64@1.20.0: 1182 | version "1.20.0" 1183 | resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.20.0.tgz#0416a0cb840944ea4aee972df02491c0168a784c" 1184 | integrity sha512-aYEohJTlzwB8URJaNiS57tMbjyLub0mYvxlxKQk8SZv+irXx6MoBWpDNQKKTS9gg1pGf/eAwjpa3BLAoCBsh1A== 1185 | 1186 | lightningcss-darwin-x64@1.20.0: 1187 | version "1.20.0" 1188 | resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.20.0.tgz#4caa2b38fe223eabb32ebc3e1268a6b09e6b8d06" 1189 | integrity sha512-cmMgY8FFWVaGgtift7eKKkHMqlz9O09/yTdlCXEDOeDP9yeo6vHOBTRP7ojb368kjw8Ew3l0L2uT1Gtx56eNkg== 1190 | 1191 | lightningcss-linux-arm-gnueabihf@1.20.0: 1192 | version "1.20.0" 1193 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.20.0.tgz#3e999a07aa77c10a06c9dda9b507c7a737f8521f" 1194 | integrity sha512-/m+NDO1O6JCv7R9F0XWlXcintQHx4MPNU+kt8jZJO07LLdGwCfvjN31GVcwVPlStnnx/cU8uTTmax6g/Qu/whg== 1195 | 1196 | lightningcss-linux-arm64-gnu@1.20.0: 1197 | version "1.20.0" 1198 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.20.0.tgz#8b7786936ea462f744a85038fb033cc56049b677" 1199 | integrity sha512-gtXoa6v0HvMRLbev6Hsef0+Q5He7NslB+Rs7G49Y5LUSdJeGIATEN+j8JzHC0DnxCsOGbEgGRmvtJzzYDkkluw== 1200 | 1201 | lightningcss-linux-arm64-musl@1.20.0: 1202 | version "1.20.0" 1203 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.20.0.tgz#8d812309c4e70398cee79fcdc452548ca521a6eb" 1204 | integrity sha512-Po7XpucM1kZnkiyd2BNwTExSDcZ8jm8uB9u+Sq44qjpkf5f75jreQwn3DQm9I1t5C6tB9HGt30HExMju9umJBQ== 1205 | 1206 | lightningcss-linux-x64-gnu@1.20.0: 1207 | version "1.20.0" 1208 | resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.20.0.tgz#7652fbb26e50a5fa21b763aaebdb4bc657540c7e" 1209 | integrity sha512-8yR/fGNn/P0I+Lc3PK+VWPET/zdSpBfHFIG0DJ38TywMbItVKvnFvoTBwnIm4LqBz7g2G2dDexnNP95za2Ll8g== 1210 | 1211 | lightningcss-linux-x64-musl@1.20.0: 1212 | version "1.20.0" 1213 | resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.20.0.tgz#aa21957fc51c363b4436e973911d01af4bed3c35" 1214 | integrity sha512-EmpJ+VkPZ8RACiB4m+l8TmapmE1W2UvJKDHE+ML/3Ihr9tRKUs3CibfnQTFZC8aSsrxgXagDAN+PgCDDhIyriA== 1215 | 1216 | lightningcss-win32-x64-msvc@1.20.0: 1217 | version "1.20.0" 1218 | resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.20.0.tgz#dcec3f7e03deda94504c93a9a03aec0484a5d5eb" 1219 | integrity sha512-BRdPvbq7Cc1qxAzp2emqWJHrqsEkf4ggxS29VOnxT7jhkdHKU+a26OVMjvm/OL0NH0ToNOZNAPvHMSexiEgBeA== 1220 | 1221 | lightningcss@^1.16.1: 1222 | version "1.20.0" 1223 | resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.20.0.tgz#efa36a52feae9b0c8537c8e650a7819f549a4a23" 1224 | integrity sha512-4bj8aP+Vi+or8Gwq/hknmicr4PmA8D9uL/3qY0N0daX5vYBMYERGI6Y93nzoeRgQMULq+gtrN/FvJYtH0xNN8g== 1225 | dependencies: 1226 | detect-libc "^1.0.3" 1227 | optionalDependencies: 1228 | lightningcss-darwin-arm64 "1.20.0" 1229 | lightningcss-darwin-x64 "1.20.0" 1230 | lightningcss-linux-arm-gnueabihf "1.20.0" 1231 | lightningcss-linux-arm64-gnu "1.20.0" 1232 | lightningcss-linux-arm64-musl "1.20.0" 1233 | lightningcss-linux-x64-gnu "1.20.0" 1234 | lightningcss-linux-x64-musl "1.20.0" 1235 | lightningcss-win32-x64-msvc "1.20.0" 1236 | 1237 | lines-and-columns@^1.1.6: 1238 | version "1.2.4" 1239 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" 1240 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== 1241 | 1242 | lmdb@2.7.11: 1243 | version "2.7.11" 1244 | resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.7.11.tgz#a24b6d36b5c7ed9889cc2d9e103fdd3f5e144d7e" 1245 | integrity sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw== 1246 | dependencies: 1247 | msgpackr "1.8.5" 1248 | node-addon-api "^4.3.0" 1249 | node-gyp-build-optional-packages "5.0.6" 1250 | ordered-binary "^1.4.0" 1251 | weak-lru-cache "^1.2.2" 1252 | optionalDependencies: 1253 | "@lmdb/lmdb-darwin-arm64" "2.7.11" 1254 | "@lmdb/lmdb-darwin-x64" "2.7.11" 1255 | "@lmdb/lmdb-linux-arm" "2.7.11" 1256 | "@lmdb/lmdb-linux-arm64" "2.7.11" 1257 | "@lmdb/lmdb-linux-x64" "2.7.11" 1258 | "@lmdb/lmdb-win32-x64" "2.7.11" 1259 | 1260 | mdn-data@2.0.14: 1261 | version "2.0.14" 1262 | resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" 1263 | integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== 1264 | 1265 | micromatch@^4.0.5: 1266 | version "4.0.5" 1267 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" 1268 | integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== 1269 | dependencies: 1270 | braces "^3.0.2" 1271 | picomatch "^2.3.1" 1272 | 1273 | minimatch@^3.1.1: 1274 | version "3.1.2" 1275 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 1276 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 1277 | dependencies: 1278 | brace-expansion "^1.1.7" 1279 | 1280 | mithril@^2.2.2: 1281 | version "2.2.2" 1282 | resolved "https://registry.yarnpkg.com/mithril/-/mithril-2.2.2.tgz#5a0743bd04726cc1efa6e91477f995d80fc6c539" 1283 | integrity sha512-YRm6eLv2UUaWaWHdH8L+desW9+DN7+oM34CxJv6tT2e1lNVue8bxQlknQeDRn9aKlO8sIujm2wqUHwM+Hb1wGQ== 1284 | dependencies: 1285 | ospec "4.0.0" 1286 | 1287 | msgpackr-extract@^1.0.14: 1288 | version "1.0.16" 1289 | resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-1.0.16.tgz#701c4f6e6f25c100ae84557092274e8fffeefe45" 1290 | integrity sha512-fxdRfQUxPrL/TizyfYfMn09dK58e+d65bRD/fcaVH4052vj30QOzzqxcQIS7B0NsqlypEQ/6Du3QmP2DhWFfCA== 1291 | dependencies: 1292 | nan "^2.14.2" 1293 | node-gyp-build "^4.2.3" 1294 | 1295 | msgpackr-extract@^3.0.1: 1296 | version "3.0.2" 1297 | resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz#e05ec1bb4453ddf020551bcd5daaf0092a2c279d" 1298 | integrity sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A== 1299 | dependencies: 1300 | node-gyp-build-optional-packages "5.0.7" 1301 | optionalDependencies: 1302 | "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.2" 1303 | "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.2" 1304 | "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.2" 1305 | "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.2" 1306 | "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" 1307 | "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" 1308 | 1309 | msgpackr@1.8.5: 1310 | version "1.8.5" 1311 | resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.5.tgz#8cadfb935357680648f33699d0e833c9179dbfeb" 1312 | integrity sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg== 1313 | optionalDependencies: 1314 | msgpackr-extract "^3.0.1" 1315 | 1316 | msgpackr@^1.5.4: 1317 | version "1.5.5" 1318 | resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.5.5.tgz#c0562abc2951d7e29f75d77a8656b01f103a042c" 1319 | integrity sha512-JG0V47xRIQ9pyUnx6Hb4+3TrQoia2nA3UIdmyTldhxaxtKFkekkKpUW/N6fwHwod9o4BGuJGtouxOk+yCP5PEA== 1320 | optionalDependencies: 1321 | msgpackr-extract "^1.0.14" 1322 | 1323 | nan@^2.14.2: 1324 | version "2.15.0" 1325 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" 1326 | integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== 1327 | 1328 | node-addon-api@^3.2.1: 1329 | version "3.2.1" 1330 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" 1331 | integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== 1332 | 1333 | node-addon-api@^4.3.0: 1334 | version "4.3.0" 1335 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" 1336 | integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== 1337 | 1338 | node-gyp-build-optional-packages@5.0.6: 1339 | version "5.0.6" 1340 | resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz#2949f5cc7dace3ac470fa2ff1a37456907120a1d" 1341 | integrity sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw== 1342 | 1343 | node-gyp-build-optional-packages@5.0.7: 1344 | version "5.0.7" 1345 | resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3" 1346 | integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w== 1347 | 1348 | node-gyp-build@^4.2.3, node-gyp-build@^4.3.0: 1349 | version "4.3.0" 1350 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" 1351 | integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== 1352 | 1353 | node-releases@^2.0.2: 1354 | version "2.0.2" 1355 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" 1356 | integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== 1357 | 1358 | nth-check@^2.0.1: 1359 | version "2.0.1" 1360 | resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" 1361 | integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== 1362 | dependencies: 1363 | boolbase "^1.0.0" 1364 | 1365 | nullthrows@^1.1.1: 1366 | version "1.1.1" 1367 | resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" 1368 | integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== 1369 | 1370 | once@^1.3.0: 1371 | version "1.4.0" 1372 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1373 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 1374 | dependencies: 1375 | wrappy "1" 1376 | 1377 | ordered-binary@^1.4.0: 1378 | version "1.4.0" 1379 | resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.4.0.tgz#6bb53d44925f3b8afc33d1eed0fa15693b211389" 1380 | integrity sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ== 1381 | 1382 | ospec@4.0.0: 1383 | version "4.0.0" 1384 | resolved "https://registry.yarnpkg.com/ospec/-/ospec-4.0.0.tgz#7aaf8cb6d352a3f22e879460eebbc5f12df99779" 1385 | integrity sha512-MpDtkpscOxHYb4w71v7GB4LBsRuzxZnM+HdwjhzJQzu+5EJvA80yxTaKw+wp5Dmf5RV2/Bg3Uvz2vlI/PhW9Ow== 1386 | dependencies: 1387 | glob "^7.1.3" 1388 | 1389 | parcel@^2.9.1: 1390 | version "2.9.1" 1391 | resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.9.1.tgz#aac949aa5533ce4e8c209e9a69afc0256fb1dc6b" 1392 | integrity sha512-LBD+jeCpvnDJ8MeE0ciEns4EZw+WH01qLEKT2O1tW2uHM1njhcWvuc9bx19f8iyE2+8Xwwr2GsGTQgPXKiA/yQ== 1393 | dependencies: 1394 | "@parcel/config-default" "2.9.1" 1395 | "@parcel/core" "2.9.1" 1396 | "@parcel/diagnostic" "2.9.1" 1397 | "@parcel/events" "2.9.1" 1398 | "@parcel/fs" "2.9.1" 1399 | "@parcel/logger" "2.9.1" 1400 | "@parcel/package-manager" "2.9.1" 1401 | "@parcel/reporter-cli" "2.9.1" 1402 | "@parcel/reporter-dev-server" "2.9.1" 1403 | "@parcel/reporter-tracer" "2.9.1" 1404 | "@parcel/utils" "2.9.1" 1405 | chalk "^4.1.0" 1406 | commander "^7.0.0" 1407 | get-port "^4.2.0" 1408 | 1409 | parent-module@^1.0.0: 1410 | version "1.0.1" 1411 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 1412 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 1413 | dependencies: 1414 | callsites "^3.0.0" 1415 | 1416 | parse-json@^5.0.0: 1417 | version "5.2.0" 1418 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" 1419 | integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== 1420 | dependencies: 1421 | "@babel/code-frame" "^7.0.0" 1422 | error-ex "^1.3.1" 1423 | json-parse-even-better-errors "^2.3.0" 1424 | lines-and-columns "^1.1.6" 1425 | 1426 | path-is-absolute@^1.0.0: 1427 | version "1.0.1" 1428 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1429 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 1430 | 1431 | path-type@^4.0.0: 1432 | version "4.0.0" 1433 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 1434 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 1435 | 1436 | picocolors@^1.0.0: 1437 | version "1.0.0" 1438 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 1439 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 1440 | 1441 | picomatch@^2.3.1: 1442 | version "2.3.1" 1443 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 1444 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 1445 | 1446 | postcss-value-parser@^4.2.0: 1447 | version "4.2.0" 1448 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" 1449 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== 1450 | 1451 | posthtml-parser@^0.10.1: 1452 | version "0.10.2" 1453 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.2.tgz#df364d7b179f2a6bf0466b56be7b98fd4e97c573" 1454 | integrity sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg== 1455 | dependencies: 1456 | htmlparser2 "^7.1.1" 1457 | 1458 | posthtml-parser@^0.11.0: 1459 | version "0.11.0" 1460 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.11.0.tgz#25d1c7bf811ea83559bc4c21c189a29747a24b7a" 1461 | integrity sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw== 1462 | dependencies: 1463 | htmlparser2 "^7.1.1" 1464 | 1465 | posthtml-render@^3.0.0: 1466 | version "3.0.0" 1467 | resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205" 1468 | integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA== 1469 | dependencies: 1470 | is-json "^2.0.1" 1471 | 1472 | posthtml@^0.16.4, posthtml@^0.16.5: 1473 | version "0.16.6" 1474 | resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.6.tgz#e2fc407f67a64d2fa3567afe770409ffdadafe59" 1475 | integrity sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ== 1476 | dependencies: 1477 | posthtml-parser "^0.11.0" 1478 | posthtml-render "^3.0.0" 1479 | 1480 | react-error-overlay@6.0.9: 1481 | version "6.0.9" 1482 | resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" 1483 | integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== 1484 | 1485 | react-refresh@^0.9.0: 1486 | version "0.9.0" 1487 | resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" 1488 | integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== 1489 | 1490 | regenerator-runtime@^0.13.7: 1491 | version "0.13.9" 1492 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" 1493 | integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== 1494 | 1495 | resolve-from@^4.0.0: 1496 | version "4.0.0" 1497 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 1498 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 1499 | 1500 | safe-buffer@^5.0.1: 1501 | version "5.2.1" 1502 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1503 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1504 | 1505 | semver@^5.7.0, semver@^5.7.1: 1506 | version "5.7.1" 1507 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1508 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1509 | 1510 | source-map@^0.6.1: 1511 | version "0.6.1" 1512 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1513 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 1514 | 1515 | srcset@4: 1516 | version "4.0.0" 1517 | resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4" 1518 | integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw== 1519 | 1520 | stable@^0.1.8: 1521 | version "0.1.8" 1522 | resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" 1523 | integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== 1524 | 1525 | supports-color@^5.3.0: 1526 | version "5.5.0" 1527 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1528 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1529 | dependencies: 1530 | has-flag "^3.0.0" 1531 | 1532 | supports-color@^7.1.0: 1533 | version "7.2.0" 1534 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1535 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1536 | dependencies: 1537 | has-flag "^4.0.0" 1538 | 1539 | svgo@^2.4.0: 1540 | version "2.8.0" 1541 | resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" 1542 | integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== 1543 | dependencies: 1544 | "@trysound/sax" "0.2.0" 1545 | commander "^7.2.0" 1546 | css-select "^4.1.3" 1547 | css-tree "^1.1.3" 1548 | csso "^4.2.0" 1549 | picocolors "^1.0.0" 1550 | stable "^0.1.8" 1551 | 1552 | term-size@^2.2.1: 1553 | version "2.2.1" 1554 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" 1555 | integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== 1556 | 1557 | timsort@^0.3.0: 1558 | version "0.3.0" 1559 | resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" 1560 | integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= 1561 | 1562 | to-regex-range@^5.0.1: 1563 | version "5.0.1" 1564 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1565 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1566 | dependencies: 1567 | is-number "^7.0.0" 1568 | 1569 | tslib@^2.4.0: 1570 | version "2.4.0" 1571 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" 1572 | integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== 1573 | 1574 | type-fest@^0.20.2: 1575 | version "0.20.2" 1576 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 1577 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 1578 | 1579 | typescript@^5.1.3: 1580 | version "5.1.3" 1581 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826" 1582 | integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw== 1583 | 1584 | utility-types@^3.10.0: 1585 | version "3.10.0" 1586 | resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" 1587 | integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== 1588 | 1589 | weak-lru-cache@^1.2.2: 1590 | version "1.2.2" 1591 | resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz#fdbb6741f36bae9540d12f480ce8254060dccd19" 1592 | integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw== 1593 | 1594 | wrappy@1: 1595 | version "1.0.2" 1596 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1597 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 1598 | 1599 | xxhash-wasm@^0.4.2: 1600 | version "0.4.2" 1601 | resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79" 1602 | integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA== 1603 | 1604 | yaml@^1.10.0: 1605 | version "1.10.2" 1606 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" 1607 | integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== 1608 | --------------------------------------------------------------------------------