diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml
new file mode 100644
index 00000000..6f6b3a57
--- /dev/null
+++ b/.github/workflows/deploy-pages.yml
@@ -0,0 +1,51 @@
+name: Deploy to GitHub Pages
+
+on:
+ push:
+ branches: [main, master]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: true
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ cache: npm
+ cache-dependency-path: denver-happy-hours/frontend/package-lock.json
+
+ - name: Install dependencies
+ working-directory: denver-happy-hours/frontend
+ run: npm ci
+
+ - name: Build
+ working-directory: denver-happy-hours/frontend
+ run: npm run build
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: denver-happy-hours/frontend/dist
+
+ deploy:
+ needs: build
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/1_warmup/empireofryan/01_first_warmup/README.md b/1_warmup/empireofryan/01_first_warmup/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/1_warmup/empireofryan/02_second_warmup/README.md b/1_warmup/empireofryan/02_second_warmup/README.md
new file mode 100644
index 00000000..0c8dedf4
--- /dev/null
+++ b/1_warmup/empireofryan/02_second_warmup/README.md
@@ -0,0 +1 @@
+Number two down.
\ No newline at end of file
diff --git a/denver-happy-hours/.gitignore b/denver-happy-hours/.gitignore
new file mode 100644
index 00000000..c2658d7d
--- /dev/null
+++ b/denver-happy-hours/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/denver-happy-hours/data/confirmed-venues.json b/denver-happy-hours/data/confirmed-venues.json
new file mode 100644
index 00000000..1f696e51
--- /dev/null
+++ b/denver-happy-hours/data/confirmed-venues.json
@@ -0,0 +1,339 @@
+[
+ {
+ "id": "wynkoop-brewing-company",
+ "name": "Wynkoop Brewing Company",
+ "address": "1634 18th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://wynkoop.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Pulled Chicken Tacos (roasted corn pico, cotija, cilantro)",
+ "Food specials starting at $5"
+ ],
+ "drink_deals": [
+ "$2 off all Wynkoop beers",
+ "$2 off house wines",
+ "$2 off well drinks"
+ ]
+ }
+ },
+ {
+ "id": "terminal-bar",
+ "name": "Terminal Bar",
+ "address": "1701 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://terminalbardenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$5.50 select draught beer",
+ "$7 well spirits",
+ "$7.50 house wines"
+ ]
+ }
+ },
+ {
+ "id": "herbs-hideout",
+ "name": "Herb's Hideout",
+ "address": "2057 Larimer St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "http://www.herbsbar.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [
+ "$2 Tacos (Monday)",
+ "1/2 priced appetizers"
+ ],
+ "drink_deals": [
+ "$3 wells & domestic pints",
+ "$4 You Call It (top shelf excluded)",
+ "$2 Coors Light drafts",
+ "$5 daily shot specials"
+ ]
+ }
+ },
+ {
+ "id": "the-cruise-room",
+ "name": "The Cruise Room",
+ "address": "1600 17th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.theoxfordhotel.com/eat-drink/the-cruise-room",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "5:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "Captain's Call \u2014 bartender's choice cocktail"
+ ]
+ }
+ },
+ {
+ "id": "viewhouse-ballpark",
+ "name": "ViewHouse Eatery, Bar & Rooftop",
+ "address": "2015 Market St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "https://www.viewhouse.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Sweet Potato Fries",
+ "$5 Chips and Salsa",
+ "$7 Bee Sting Cauliflower",
+ "$7 Pork Green Chili"
+ ],
+ "drink_deals": [
+ "$4 Bud/Coors Light",
+ "$4 well gin/rum/vodka/whiskey",
+ "$6 craft drafts",
+ "$8 signature cocktails (margaritas, mules, palomas)"
+ ]
+ }
+ },
+ {
+ "id": "nallens-irish-pub",
+ "name": "Nallen's Irish Pub",
+ "address": "1429 Market St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": null,
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "2:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [],
+ "drink_deals": [
+ "$1 off all drinks",
+ "$3 Bud Light Drafts",
+ "$4 Carbombs"
+ ]
+ }
+ },
+ {
+ "id": "the-1up-lodo",
+ "name": "The 1UP Arcade Bar - LoDo",
+ "address": "1925 Blake St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://the1uparcadebar.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$2 Coors Light Draft",
+ "$3 Pickle Shots",
+ "$3 well liquor",
+ "$5 Jack Daniel's / Tito's / Herradura",
+ "$6 1UP IPA Drafts",
+ "$1 off all cans"
+ ]
+ }
+ },
+ {
+ "id": "linger",
+ "name": "Linger",
+ "address": "2030 W 30th Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://lingerdenver.com",
+ "happy_hour": {
+ "days": [
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$7 French onion mussels",
+ "$5.50 Wagyu slider",
+ "$4 Mongolian BBQ duck bun",
+ "$5 Sweet potato waffle fries",
+ "$3.50 Jerk chicken lettuce wrap"
+ ],
+ "drink_deals": [
+ "$4 select draft beer",
+ "$5 house wine",
+ "$5 Red sangria",
+ "$5 cocktails (Ginger collins, Coconut daiquiri, Whiskey daisy)"
+ ]
+ }
+ },
+ {
+ "id": "avanti-food-beverage",
+ "name": "Avanti Food & Beverage",
+ "address": "3200 Pecos St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.avantifandb.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "2:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$4 Upslope Snowmelt Seltzer",
+ "$5 Odell Lagerado",
+ "$6 Avery IPA",
+ "$6 house wine",
+ "$6 house spirits",
+ "$7 Jack Daniel's"
+ ]
+ }
+ },
+ {
+ "id": "highland-tap-and-burger",
+ "name": "Highland Tap and Burger",
+ "address": "2219 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://tapandburger.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$4 Hand Cut Fries w/ truffled aioli",
+ "$5 Chili Cheese Fries",
+ "$5 Steak Tacos (2)",
+ "$5 Sliders (choose 2)"
+ ],
+ "drink_deals": [
+ "$3 select draft beers",
+ "1/2 off bottles of house wine",
+ "$5 Moscow Mules / Dark 'n Stormy / Coin Margarita",
+ "$5 Jameson Irish Whiskey"
+ ]
+ }
+ },
+ {
+ "id": "el-camino-community-tavern",
+ "name": "El Camino Community Tavern",
+ "address": "3628 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://elcaminotavern.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "$8 Green chili nachos",
+ "$6 Shishito peppers",
+ "$7 Mini guac & chili con queso"
+ ],
+ "drink_deals": [
+ "$2 Tecate",
+ "$5 ALE camino",
+ "$6 El Camino margarita",
+ "$7 Deer-&-beer (Imperial + Cazadores shot)",
+ "$6 wine by the glass"
+ ]
+ }
+ },
+ {
+ "id": "senor-bear",
+ "name": "Se\u00f1or Bear",
+ "address": "3301 Tejon St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://senorbeardenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$1.25 chicken wing confit (each)",
+ "$3.50 Gordo Crunch",
+ "$4 Mezcla de Fiesta (snack mix)",
+ "$4.50 Latin Pizza",
+ "$5.50 Seafood tostada"
+ ],
+ "drink_deals": [
+ "$3 Tecate",
+ "$4 Michelada",
+ "$5 Margarita / Paloma / Pisco sour",
+ "$5 daily wine (red or white)"
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/denver-happy-hours/data/crawl-results-lodo1.json b/denver-happy-hours/data/crawl-results-lodo1.json
new file mode 100644
index 00000000..bc339a31
--- /dev/null
+++ b/denver-happy-hours/data/crawl-results-lodo1.json
@@ -0,0 +1,132 @@
+[
+ {
+ "id": "falling-rock-tap-house",
+ "name": "Falling Rock Tap House",
+ "source": "https://www.yelp.com/biz/falling-rock-tap-house-denver",
+ "days": "PERMANENTLY CLOSED",
+ "start_time": "N/A",
+ "end_time": "N/A",
+ "food_deals": "N/A",
+ "drink_deals": "N/A",
+ "notes": "Falling Rock Tap House permanently closed in June 2021 after 24 years at 1919 Blake St. Confirmed closed by Yelp (updated Aug 2025), Denver Post, 9News, CBS Colorado, and Denver7. The closure was attributed to COVID-19 impacts, a construction project that caused 30% sales drop, and neighborhood changes. Their website (fallingrocktaphouse.com) still returns a 503 error. This venue should be removed from the aggregator."
+ },
+ {
+ "id": "wynkoop-brewing",
+ "name": "Wynkoop Brewing Company",
+ "source": "https://wynkoop.com",
+ "source_search": "https://www.yelp.com/biz/wynkoop-brewing-denver-2",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Pulled Chicken Tacos (roasted corn pico, cotija, cilantro)",
+ "Food specials starting at $5 (full menu on PDF at wynkoop.com/wp-content/uploads/menus/happyhour.pdf - PDF was not machine-readable)"
+ ],
+ "drink_deals": [
+ "$2 off all Wynkoop beers",
+ "$2 off house wines",
+ "$2 off well drinks"
+ ],
+ "notes": "Located at 1634 18th St, Denver, CO 80202. Colorado's first brewpub (est. 1988). Open daily at 11 AM. The happy hour PDF menu exists at wynkoop.com/wp-content/uploads/menus/happyhour.pdf but could not be parsed (binary/image PDF). The website homepage confirms '$2.00 off select beers, wines and well drinks along with food specials starting at $5'. Web search results confirmed Mon-Fri 3-6 PM. Also offers free pool Mon-Tue 11 AM-4 PM. Phone: 303-297-2700."
+ },
+ {
+ "id": "terminal-bar",
+ "name": "Terminal Bar",
+ "source": "https://ultimatehappyhours.com/restaurants/terminal-bar/",
+ "source_search": "https://ingoodtastedenver.com/happy-hour-deals-for-2025/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$5.50 select draught beer (Ultimate Happy Hours, updated 06/22/25)",
+ "$7.00 well spirits (Ultimate Happy Hours, updated 06/22/25)",
+ "$7.50 house wines (Ultimate Happy Hours, updated 06/22/25)"
+ ],
+ "notes": "Located at 1701 Wynkoop St inside Denver Union Station's Great Hall, next to the Crawford Hotel. The original website (theterminalbar.com) domain is for sale; the active site is terminalbardenver.com (returned 503 errors during crawl). The In Good Taste Denver 2025 guide listed slightly different prices: $6 select draught, $7 well spirits, $7 house wines. Happy hour is available anywhere inside Terminal Bar, the Beer Garden benches, and from the Beer Window for takeaway in the Great Hall. Friday evenings feature live piano music 6-9 PM. 30 Colorado craft beers on tap. No food specials were found on any source. Phone: 720-460-3701."
+ },
+ {
+ "id": "herbs-hideout",
+ "name": "Herb's Hideout",
+ "source": "https://thehappyhourfinder.com/us_co/denver/herbs-hideout/",
+ "source_website": "http://www.herbsbar.com/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "unknown - see notes",
+ "end_time": "unknown - see notes",
+ "food_deals": [
+ "$2 Tacos (Monday special)",
+ "1/2 priced appetizers (daily)",
+ "$7 select appetizers (weekday 3-7 PM window)"
+ ],
+ "drink_deals": [
+ "$3 Wells & domestic pints (weekday 3-6 PM)",
+ "$4 Smirnoff, Jack Tennessee Fire, house wines (weekday 3-6 PM)",
+ "$4 You Call It - top shelf excluded (daily 4-7 PM)",
+ "$3 Domestics (daily)",
+ "$4 Single Wells (daily)",
+ "$6 Double Wells (daily)",
+ "$6 Long Islands (daily)",
+ "$5 daily shot specials",
+ "$2 Coors Light drafts (weekday 3-7 PM)",
+ "$3 You Call It (weekday 3-7 PM)",
+ "$3 Jager & Fireball (Monday)",
+ "$2.50 Wells & domestics (Monday)",
+ "$3 Shock Top (Monday)"
+ ],
+ "notes": "Located at 2057 Larimer St, Denver, CO 80205. IMPORTANT DATA QUALITY NOTE: The happy hour data comes from Happy Hour Finder aggregator, which lists multiple overlapping time windows (11 AM-7 PM, 3-6 PM, 3-7 PM, 4-7 PM) that may reflect different periods or data updates rather than concurrent specials. Herb's official website (herbsbar.com) and their Downtown Denver Bars listing do NOT list specific happy hour details. Yelp lists hours as Mon-Sat 5 PM-2 AM, Sun 3 PM-2 AM, which conflicts with some of the earlier happy hour start times listed on aggregators. The aggregator data may be outdated. Best to call (303) 299-9555 or (303) 296-9733 to confirm current specials. Musician-owned venue known for live music. Best of Denver 2025 Winner. Never a cover charge."
+ },
+ {
+ "id": "the-cruise-room",
+ "name": "The Cruise Room",
+ "source": "https://www.theoxfordhotel.com/eat-drink/the-cruise-room",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "5:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "Captain's Call - bartender's choice cocktail (price not published)"
+ ],
+ "notes": "Located at 1600 17th St inside The Oxford Hotel, Denver, CO 80202. Denver's longest-running bar, opened the day after Prohibition was repealed in 1933. Art Deco design inspired by the RMS Queen Mary. The 'Captain's Call' is their version of happy hour - a bartender's choice cocktail available Mon-Fri 5-6 PM. No specific pricing was found on any source (website, Yelp, Foursquare, TripAdvisor, Drink Denver, or Sage Menu). The venue is listed at $$$ price level. Regular hours: Mon-Thu 4 PM-11 PM, Fri-Sat 4 PM-12 AM, Sun 4 PM-10 PM. No reservations accepted, walk-in only. This is NOT a traditional happy hour with discounted drinks - it is a single featured cocktail chosen by the bartender. Phone: (303) 262-6070."
+ },
+ {
+ "id": "viewhouse-ballpark",
+ "name": "ViewHouse Eatery, Bar & Rooftop (Ballpark)",
+ "source": "https://www.viewhouse.com/events/5-7-9-happy-hour",
+ "source_search": "https://denver.thedrinknation.com/bars/profile/3736-ViewHouse-Eatery-Bar-Rooftop-Ballpark",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Sweet Potato Fries",
+ "$5 Onion Rings",
+ "$5 Chips and Salsa",
+ "$7 Kichin Pigs In A Blanket",
+ "$7 Bee Sting Cauliflower",
+ "$7 Caesar Salad",
+ "$7 Pork Green Chili"
+ ],
+ "drink_deals": [
+ "$4 Bud Light",
+ "$4 Coors Light",
+ "$4 VH Beer Rockpile Red Ale",
+ "$4 Gin (well)",
+ "$4 Rum (well)",
+ "$4 Vodka (well)",
+ "$4 Jack Daniel's",
+ "$4 Barefoot Wine",
+ "$6 VH Beer 1858 IPA",
+ "$6 VH Beer Ballpark Pale Ale",
+ "$6 VH Beer Peach Buzz Blonde Ale",
+ "$6 VH Beer Que Pasa Mexi Lager",
+ "$6 Odell Mountain Standard Hazy IPA",
+ "$8 Spicy Blackberry Margarita",
+ "$8 VH Mule",
+ "$8 Cucumber Fresca",
+ "$8 VH Lemonade",
+ "$8 Viewhouse Margarita",
+ "$8 Dusty Rose Margarita",
+ "$8 Skinny Paloma"
+ ],
+ "notes": "Located at 2015 Market St, Denver, CO 80205. ViewHouse advertises their happy hour as '$5 | $7 | $9' tiers, though actual prices found from web search show $4/$6/$8 drink tiers and $5/$7 food tiers. The viewhouse.com website returned 403 errors during direct crawl, so data was obtained from web search results referencing their official menu pages. Independently owned, chef-driven, with 4 Colorado locations. 35 local taps, 15 local distilleries, 40 house-made cocktails. Also offers Thursday Ladies Night 9 PM-12 AM (free well drinks, house wines, draft beers for women; live DJ). The full happy hour menu is at viewhouse.com/menus/happy-hour. Phone: (720) 878-2015."
+ }
+]
diff --git a/denver-happy-hours/data/crawl-results-lodo2.json b/denver-happy-hours/data/crawl-results-lodo2.json
new file mode 100644
index 00000000..cef37249
--- /dev/null
+++ b/denver-happy-hours/data/crawl-results-lodo2.json
@@ -0,0 +1,115 @@
+[
+ {
+ "id": "nallens-irish-pub",
+ "name": "Nallen's Irish Pub",
+ "source": "https://www.milehighhappyhour.com/lower-downtown/nallens-irish-pub/ , https://pubcrawls.com/venues/denver/nallens-irish-pub/ , https://www.totalhappyhour.com/happy-hour-for-nallens-irish-pub-in-denver-co-80202/",
+ "crawl_note": "Official site nallensirishpub.com had SSL errors; nallenspubdenver.com also had SSL errors. Data gathered from aggregator sites.",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "2:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "none - no kitchen on premises",
+ "drink_deals": [
+ "$1 off all drinks",
+ "$3 Bud Light Drafts",
+ "$4 Carbombs"
+ ],
+ "notes": "Denver's oldest Irish pub, open since 1992. Located at 1429 Market St, Denver, CO 80202. Open daily 2:00 PM - 2:00 AM. No food served (no kitchen), but guests can bring their own. Some sources list happy hour ending at 8:00 PM rather than 7:00 PM - call (303) 572-0667 to confirm current times. Prices sourced from aggregator sites and may not reflect the latest changes."
+ },
+ {
+ "id": "star-bar-denver",
+ "name": "Star Bar Denver",
+ "source": "https://www.thestarbardenver.com , https://www.milehighhappyhour.com/five-points/star-bar/ , https://denver.thedrinknation.com/bars/profile/2318-Star-Bar , https://www.downtowndenverbars.com/five-points/star-bar.html",
+ "crawl_note": "Official site thestarbardenver.com returned limited content. Has a /drinkdeals page but it did not render deal specifics. Mile High Happy Hour states: 'Currently, we do not know any happy hours here.' Multiple sources confirm 'low prices and happy hour deals' exist but no specific times or prices are publicly listed online.",
+ "days": "unknown",
+ "start_time": "unknown",
+ "end_time": "unknown",
+ "food_deals": "none - does not serve food",
+ "drink_deals": "unknown",
+ "notes": "Established 1959, one of Denver's oldest bars. Located at 2137 Larimer St, Denver, CO 80205. Open Tue-Sun 4:00 PM - 2:00 AM, closed Mondays. Opens 11:00 AM on Rockies home game days. Average drink price $3-$5. Foursquare user tips mention Rockies game day deals: 20oz Coors Light $3 and 20oz Dale's Pale Ale $4, but these are not confirmed current specials. Features karaoke Tue/Thu at 9pm, live music most weekends, $0.50 pool. Does not serve food. Contact (720) 328-2420 or starbardenver@gmail.com for current specials."
+ },
+ {
+ "id": "the-1up-lodo",
+ "name": "The 1UP Arcade Bar - LoDo",
+ "source": "https://the1uparcadebar.com/pages/menus",
+ "crawl_note": "Data sourced from official menus page at the1uparcadebar.com. This is current, directly from the venue's own website.",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown - no specific food happy hour deals listed; partners with Sliceworks Pizza for food",
+ "drink_deals": [
+ "$2 Coors Light Draft",
+ "$3 Pickle Shots",
+ "$3 Mystery Shots",
+ "$3 Well Liquor (vodka, rum, gin, tequila, whiskey)",
+ "$4 Red Bull Energy Drinks & Editions",
+ "$5 Jack Daniel's",
+ "$5 Tullamore D.E.W.",
+ "$5 Tito's Vodka",
+ "$5 Herradura Tequila",
+ "$5 Sailor Jerry Rum",
+ "$5 Fords Gin",
+ "$6 1up IPA Drafts",
+ "$1 off all cans"
+ ],
+ "daily_specials": {
+ "Monday": ["$3 Modelo", "$5 Milagro Tequila"],
+ "Tuesday": ["$6 Twisted Tea", "$5 Herradura Tequila"],
+ "Wednesday": ["$2 Coors Light", "$5 Stoli Vodka", "$7 Stoli Vodka + Red Bull"],
+ "Thursday": ["$3 PBR", "$3 Pickle Shots", "$5 Tullamore Dew", "$5 Green Tea Shots"],
+ "Friday": ["$6 Tito's Vodka", "$1 off 40's"],
+ "Saturday": ["$3 Mystery Shots"],
+ "Sunday": ["$2 High Noons (12-2pm only)", "All Day Happy Hour"]
+ },
+ "notes": "Located at 1925 Blake St, Denver, CO 80202. Open Mon-Fri 3:00 PM - 2:00 AM, Sat-Sun 11:00 AM - 2:00 AM. Happy hour also runs every night 12:00 AM - close (late night happy hour). Sunday is ALL DAY happy hour. Over 45 classic arcade games, 16 pinball machines, Skee-Ball. All arcade games 25 cents, pinball 50 cents. Food from Sliceworks Pizza. Phone: (303) 736-2230."
+ },
+ {
+ "id": "great-divide-brewing",
+ "name": "Great Divide Brewery & Roadhouse - RiNo",
+ "source": "https://www.opentable.com/r/great-divide-brewery-and-roadhouse-rino-denver , https://www.greatdividebreweryandroadhouse.com/menus/happy-hour",
+ "crawl_note": "Original Great Divide Brewing Company taproom at 2201 Arapahoe St is CLOSED (confirmed on Yelp). The RiNo Roadhouse location (operated by Vibe Concepts) is the active Denver location with happy hour. Happy hour menu page at greatdividebreweryandroadhouse.com returned 403, but OpenTable provided full details. Web search results also confirmed details.",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "2:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "1/2 price appetizers during happy hour",
+ "Deviled Eggs - $7 (half price)",
+ "Thai Cauliflower - $6 (half price)",
+ "Chips, Guac & Salsa - $7 (half price)",
+ "Warm Pimento Cheese Dip - $5 (half price)",
+ "Greek Style Hummus - $7 (half price)",
+ "Brussels Sprouts - $6 (half price)",
+ "Pretzels & Queso - $7 (half price)"
+ ],
+ "drink_deals": [
+ "$5 draft beer",
+ "$5 house wine",
+ "$8 signature cocktails (Roadhouse Margarita, Whiskey Basil Smash, Peach Mule, All American Mule)"
+ ],
+ "late_night_happy_hour": {
+ "start_time": "9:00 PM",
+ "end_time": "close",
+ "drink_deals": [
+ "$5 Great Divide Lager",
+ "$7 signature cocktails"
+ ],
+ "notes": "Late night happy hour runs Mon-Thu and Sun 9 PM - 10 PM, Fri-Sat 9 PM - 11 PM per one source. Another source says 9 PM to close."
+ },
+ "weekly_specials": {
+ "Wednesday": "Wine & Whiskey Wednesday - 1/2 priced select bottles of wine and whiskey/bourbon pours all night"
+ },
+ "notes": "Located at 3040 Blake St #101, Denver, CO 80205 (RiNo neighborhood). NOTE: The original Great Divide taproom at 2201 Arapahoe St is permanently CLOSED. This Roadhouse location is operated by Vibe Concepts in partnership with Great Divide Brewing Co. Features craft beer, signature burgers, hearty entrees. All Roadhouse locations serve brunch, lunch, dinner, and happy hour daily. Contact: greatdividerino@vibeconcepts.com. Appetizer prices shown are the happy hour (half) prices."
+ },
+ {
+ "id": "jagged-mountain-craft-brewery",
+ "name": "Jagged Mountain Craft Brewery",
+ "source": "https://www.yelp.com/biz/jagged-mountain-craft-brewery-denver-2 , https://untappd.com/JaggedMountain , https://www.milehighhappyhour.com/five-points/jagged-mountain-brewery/",
+ "crawl_note": "PERMANENTLY CLOSED. Confirmed closed on both Yelp and Untappd. Mile High Happy Hour had no happy hour info even before closure.",
+ "days": "not_applicable",
+ "start_time": "not_applicable",
+ "end_time": "not_applicable",
+ "food_deals": "not_applicable",
+ "drink_deals": "not_applicable",
+ "status": "permanently_closed",
+ "notes": "Jagged Mountain Craft Brewery is PERMANENTLY CLOSED. Previously located at 1139 20th St, Denver, CO 80205. Founded in 2013, the brewery was known for small batch, high alcohol craft ales. Yelp and Untappd both confirm the closure. No current happy hour information is available. Mile High Happy Hour noted 'Currently, we do not know any happy hours here' even before closure."
+ }
+]
diff --git a/denver-happy-hours/data/crawl-results-lohi1.json b/denver-happy-hours/data/crawl-results-lohi1.json
new file mode 100644
index 00000000..48a467b1
--- /dev/null
+++ b/denver-happy-hours/data/crawl-results-lohi1.json
@@ -0,0 +1,99 @@
+[
+ {
+ "id": "linger",
+ "name": "Linger",
+ "source": "https://www.milehighhappyhour.com/highlands/linger/",
+ "days": ["Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "4:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$7 French onion mussels",
+ "$6 Raw beet hummus",
+ "$6 Popper Breakdown (shishito peppers)",
+ "$4 Mongolian BBQ duck bun",
+ "$5.50 Linger Wagyu slider",
+ "$5 Sugar snap peas",
+ "$5 Sweet potato waffle fries",
+ "$3.50 Jerk chicken lettuce wrap",
+ "$6 Devils on horseback"
+ ],
+ "drink_deals": [
+ "$4 Select draft beer",
+ "$5 House red or white wine",
+ "$5 Red sangria",
+ "$5 Ginger collins",
+ "$5 New Saigon",
+ "$5 Coconut daiquiri",
+ "$5 Whiskey daisy"
+ ],
+ "notes": "Located at 2030 W 30th Ave, Denver CO 80211. Part of Edible Beats restaurant group. Rooftop patio venue in a former mortuary. GoldenBuzz lists hours as Mon-Fri 4PM-6PM (slight discrepancy with milehighhappyhour source which says Tue-Fri 4:00-6:30 PM). The ediblebeats.com website returned 503 errors during crawling. Specials sourced from milehighhappyhour.com which may not reflect the latest menu."
+ },
+ {
+ "id": "lohi-steakbar",
+ "name": "LoHi SteakBar",
+ "source": "https://www.milehighhappyhour.com/highlands/lohi-steakbar/",
+ "days": "PERMANENTLY CLOSED",
+ "start_time": "PERMANENTLY CLOSED",
+ "end_time": "PERMANENTLY CLOSED",
+ "food_deals": "PERMANENTLY CLOSED",
+ "drink_deals": "PERMANENTLY CLOSED",
+ "notes": "LoHi SteakBar permanently closed in June 2022 after 12 years in business. Owners opted not to renew their lease. The space at 3200 Tejon St was replaced by Jacques, a French bistro, which opened in September 2023. The original domain lohisteakbar.com now redirects to an unrelated gambling website. Historical happy hour (before closure): Daily 3:00 PM-6:00 PM and 10:00 PM-Close. Drinks included 1/2 off house beer, well cocktails, and wines by the glass, plus $8 bartender choice. Food included $1 oysters on the half shell, $5 french onion dip, $5 fried shishito, $5 loaded steak fries, $6 P.E.I. mussels, $5 crab cake, $4 meatball slider, $4 steak tostado, $3 mini blue smoke burger, $5 mini steak sandwich. Sources: Westword, Denver Post, milehighhappyhour.com."
+ },
+ {
+ "id": "avanti-food-beverage",
+ "name": "Avanti Food & Beverage",
+ "source": "https://www.avantifandb.com/event/happy-hour/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "2:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$5 Odell Lagerado",
+ "$4 Upslope Snowmelt Seltzer",
+ "$6 Avery IPA",
+ "$6 House wine (red, white, or rose)",
+ "$6 House spirits (New Amsterdam gin & vodka, Bacardi rum, Benchmark bourbon, Suerte tequila)",
+ "$7 Jack Daniel's",
+ "$10 Jack & a Cold Snack (shot of Jack Daniel's + Montucky Cold Snack)"
+ ],
+ "notes": "Located at 3200 Pecos St, Denver CO 80211. Collective food hall with seven restaurant concepts and two full bars. The official happy hour page lists only drink specials - no specific food deals were found on the website or third-party sources. Bar hours: Sun-Wed 11am-11pm, Thu 11am-12am, Fri-Sat 11am-1am. Also has locations in Boulder and Vail. Drink specials confirmed directly from avantifandb.com/denver-bar and avantifandb.com/event/happy-hour/."
+ },
+ {
+ "id": "williams-and-graham",
+ "name": "Williams & Graham",
+ "source": "https://www.milehighhappyhour.com/highlands/williams-graham/",
+ "days": "none",
+ "start_time": "none",
+ "end_time": "none",
+ "food_deals": "none",
+ "drink_deals": "none",
+ "notes": "Williams & Graham does NOT offer a happy hour. This is confirmed by milehighhappyhour.com which states: 'There's a full menu of handcrafted food and cocktails, but no happy hour.' This is consistent with its identity as a high-end, internationally recognized speakeasy-style cocktail bar (World's Top 50 Bar, 2x Top Cocktail Bar in US). Located at 3160 Tejon St, Denver CO 80211. Open daily 5:00 PM-1:00 AM. Hidden behind a bookshelf in a mock bookstore. 21+ only. Features 60+ classic cocktails and 500+ spirits. Reservations accepted Sun-Thu; walk-in focused Fri-Sat. The williamsandgraham.com website returned SSL errors during direct crawling."
+ },
+ {
+ "id": "highland-tap-and-burger",
+ "name": "Highland Tap and Burger",
+ "source": "https://www.milehighhappyhour.com/highlands/highland-tap-and-burger/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$4 Hand Cut Fries with truffled aioli",
+ "$5 Chili Cheese Fries",
+ "$4 Hummus & Warm Flatbread",
+ "$5 Steak Tacos (2 soft tacos)",
+ "$5 Sliders (choose two per order - root beer pulled pork, Polidori sausage, or all natural beef)"
+ ],
+ "drink_deals": [
+ "$3 Select Draft Beers (any $5 beers are $3)",
+ "1/2 off bottles of house wines",
+ "$5 Denver Donkey (Spring 44 honey vodka, Goslings ginger beer, fresh lime juice)",
+ "$5 Moscow Mules (Spring 44 vodka, Goslings ginger beer, fresh lime juice)",
+ "$5 Dark 'n Stormy (Goslings Black Seal rum, Goslings ginger beer, fresh lime juice)",
+ "$4 Ginger Fresca (Skyy ginger vodka, Sprite, splash of OJ)",
+ "$5 Maple Sour (Spring 44 honey vodka, lemon juice, maple syrup, angostura bitters)",
+ "$5 Coin Style Margarita",
+ "$5 Jameson Irish Whiskey"
+ ],
+ "notes": "Located at 2219 W 32nd Ave, Denver CO 80211. Phone: 720-287-4493. Also offers a LATE NIGHT happy hour: Sun-Wed 10:00 PM-12:00 AM, Thu-Sat 11:00 PM-1:00 AM. Late night deals include $5 Jameson, $5 Cucumber Collins, $5 Dark 'n Stormy, and discounted food from $3.50 Chips & Salsa up to $8.50 B.Y.O. Burger & Fries. Note: 20% service charge on all checks. Pet-friendly patio. 18 TVs with every sports package. Official website is tapandburger.com. Hours: Mon-Wed 11am-10pm, Thu-Fri 11am-11pm, Sat 10am-11pm, Sun 10am-10pm. Some sources list slightly different happy hour times (3-6pm vs 3-6:30pm); the more detailed milehighhappyhour.com source is used here."
+ }
+]
diff --git a/denver-happy-hours/data/crawl-results-lohi2.json b/denver-happy-hours/data/crawl-results-lohi2.json
new file mode 100644
index 00000000..ea812b6f
--- /dev/null
+++ b/denver-happy-hours/data/crawl-results-lohi2.json
@@ -0,0 +1,156 @@
+[
+ {
+ "id": "ale-house-amatos",
+ "name": "Ale House at Amato's",
+ "source": "https://www.denverpost.com/2022/05/24/ale-house-closing-amatos-denver-lohi/, https://www.yelp.com/biz/ale-house-denver-4",
+ "days": "unknown",
+ "start_time": "unknown",
+ "end_time": "unknown",
+ "food_deals": "unknown",
+ "drink_deals": "unknown",
+ "notes": "PERMANENTLY CLOSED since April 2022. The LoHi restaurant at 2501 16th St closed after sales struggled to rebound post-pandemic. Owned by Breckenridge-Wynkoop. The space was replaced by The Hampton Social (Chicago-based restaurant). Confirmed closed by Yelp, Denver Post, The Infatuation, and The Rooftop Guide."
+ },
+ {
+ "id": "garibaldi-mexican-bistro",
+ "name": "Garibaldi Mexican Bistro",
+ "source": "https://www.garibaldimexican.com/, https://www.yelp.com/biz/garibaldi-mexican-bistro-englewood",
+ "days": "unknown",
+ "start_time": "unknown",
+ "end_time": "unknown",
+ "food_deals": "unknown",
+ "drink_deals": "unknown",
+ "notes": "No happy hour information found on their website or through web searches. This is a small takeout-oriented Mexican bistro located at 3298 S Broadway Ste B, Englewood, CO 80113 (not in Denver proper - in Englewood). Hours are Mon-Sat 10am-8pm, Sun 10am-4pm. Primarily serves Mexico City style cuisine for takeout/pickup. They do advertise a Taco Tuesday plate starting from $10.00 (3 tacos with corn tortilla, rice, beans). Phone: (303) 781-0812."
+ },
+ {
+ "id": "el-camino-community-tavern",
+ "name": "El Camino Community Tavern",
+ "source": "https://www.milehighhappyhour.com/highlands/el-camino-community-tavern/, https://www.totalhappyhour.com/happy-hour-for-el-camino-tavern-in-denver-co-80211/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "$8 green chili nachos (add carnitas, chicken, chorizo, or tempeh +$3)",
+ "$6 shishito peppers (quick fried, tossed in lemon seasoning, served with green goddess)",
+ "$7 mini guacamole & mini chili con queso"
+ ],
+ "drink_deals": [
+ "$5 ALE camino",
+ "$2 Tecate",
+ "$7 deer-&-beer (Imperial and a shot of Cazadores blanco)",
+ "$6 El Camino margarita",
+ "$8 house-infused margarita",
+ "$8 Histeria margarita (Coin-style with Herradura Silver)",
+ "$5 tequila shot (blanco)",
+ "$6 tequila shot (reposado)",
+ "$7 tequila shot (anejo)",
+ "$6 wine by the glass (red, white, or rose)"
+ ],
+ "notes": "Located at 3628 W 32nd Ave, Denver, CO 80211 (Highland Square). Open Mon-Fri 11am-11pm, Sat 10am-11pm, Sun 10am-10pm. Sources conflict on exact happy hour times: milehighhappyhour.com says daily 3pm-5pm with the prices listed above; totalhappyhour.com says 3pm-6:30pm with lower prices ($2 Pacifico, $3 house margaritas, $4 green chili nachos) plus late night happy hour Sun-Thu 10pm-midnight and Fri-Sat 10pm-1am. The milehighhappyhour.com data appears more detailed and specific. Also famous for $1 Taco Tuesdays. Their own specials page is currently being updated."
+ },
+ {
+ "id": "senor-bear",
+ "name": "Senor Bear",
+ "source": "http://places.singleplatform.com/seor-bear/menu, https://www.westword.com/restaurants/happy-hour-at-senor-bear-is-a-festive-latin-party-9972937, https://www.westword.com/restaurants/denver-happy-hour-of-the-week-at-senor-bear-11784531, https://denver.goldenbuzz.social/happy-hour/senor-bear/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$4 Mezcla de Fiesta (candied black lime cashews, garlic chile peanuts, chulpe corn, cilantro, lime)",
+ "$1.25 each chicken wing confit (with choice of sauce: spicy chipotle/jalapeno, hot green habanero, or 'ruin your day' death bear sauce)",
+ "$3.50 Gordo Crunch (flour tortilla wrapped crispy taco shell, chorizo, lettuce, jack cheese, chilies, guacamole)",
+ "$4.50 Latin Pizza",
+ "$5.50 seafood tostada (rotating ceviche with avocado, onion, tomato, aji amarillo)",
+ "$2.50 mini queso (gooey dip with pepitas)"
+ ],
+ "drink_deals": [
+ "$3 Tecate",
+ "$4 michelada",
+ "$5 margarita",
+ "$5 paloma",
+ "$5 pisco sour",
+ "$5 Cuba libre",
+ "$5 congelado del dia (daily frozen drink)",
+ "$5 daily red wine",
+ "$5 daily white wine"
+ ],
+ "notes": "Located at 3301 Tejon St, Denver, CO 80211 (LoHi). Happy hour called 'Hora Loca'. At the bar: 3-6pm; at tables: 3-5pm. The Gordo Crunch is the signature happy hour item - only available during Hora Loca. IMPORTANT: Prices listed are from SinglePlatform cached menu and Westword reviews (2018-2020). A new chef (Joe Mazzocco) joined in 2025 and is revamping the menu - some items like Gordo Crunch ($5 reported elsewhere) and Coconut Rice ($13) confirmed to remain. Current prices may differ. The restaurant adds a 20% service charge (not a tip/gratuity). Open Mon-Thu 3-10pm, Fri-Sat 3-11pm, Sun 10am-10pm. Phone: 720-572-5997. Their website (senorbeardenver.com) had SSL connection issues during crawling."
+ },
+ {
+ "id": "the-way-back",
+ "name": "The Way Back",
+ "source": "https://denver.thedrinknation.com/bars/profile/4030-The-Way-Back, https://www.opentable.com/r/the-way-back-denver, https://303magazine.com/2018/03/the-way-back-tennyson-photos/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$7 small plates",
+ "$8 small plates",
+ "$9 small plates"
+ ],
+ "drink_deals": [
+ "$4 select beers and well drinks",
+ "$5 select cocktails",
+ "$6 house wines"
+ ],
+ "notes": "STATUS UNCERTAIN. Located at 3963 Tennyson St, Denver, CO 80212. Yelp lists The Way Back as CLOSED, but OpenTable still shows hours (Tue-Sat 5-9pm as of Jan 2026) and their website (thewaybackdenver.com) is still active with menu, drinks menu, and reservations pages. The restaurant also has a Wayback Wine Shop. Known for creative, seasonal contemporary plates using locally sourced ingredients. The happy hour prices listed are from drinknation.com and 303 Magazine (2018) - they may be outdated. An earlier article mentioned happy hour featuring $3 Coors Banquet, $5 house sours, $6 house wines. Recommend calling or visiting to confirm current status and specials. Email: info@thewaybackdenver.com."
+ },
+ {
+ "id": "little-man-ice-cream",
+ "name": "Little Man Ice Cream",
+ "source": "https://www.littlemanicecream.com/, https://www.yelp.com/biz/little-man-ice-cream-denver",
+ "days": "unknown",
+ "start_time": "unknown",
+ "end_time": "unknown",
+ "food_deals": "unknown",
+ "drink_deals": "unknown",
+ "notes": "NO REGULAR HAPPY HOUR. This is an ice cream shop, not a bar/restaurant. Located at 2620 16th St, Denver, CO 80211 (iconic 28-foot-tall milk can building). Open Mon-Thu 12-10pm, Fri-Sat 12-11pm, Sun 12-10pm. They do offer seasonal ticketed experiences ($125/person) that include a 'happy hour' with charcuterie, factory tour, and take-home ice cream, but this is a special event, not a regular happy hour. Also has a Factory location at 4411 W Colfax Ave. Some locations offer boozy shakes. Established 2008. Phone: (303) 455-3811. Website returned 503 error during crawling."
+ },
+ {
+ "id": "retro-room",
+ "name": "The Retro Room Lounge & Salon",
+ "source": "https://retroroomlounge.squarespace.com/specials, https://www.milehighhappyhour.com/five-points/the-retro-room-lounge/, https://retroroomlounge.squarespace.com/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "4:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [
+ "$7 burger and a beer (all day, per their own website)",
+ "$6 wings and a beer (Wednesdays, per milehighhappyhour.com)"
+ ],
+ "drink_deals": [
+ "$4 You-Call-Its (per their own website)",
+ "House-made pickle shots (signature item, price not listed)",
+ "Scorpion shots (signature item, price not listed)"
+ ],
+ "notes": "Located at 2034 Larimer St, Denver, CO 80205 (Five Points / near Coors Field) - NOT at 1801 Wynkoop as searched. Hours: Mon 4pm-2am, Tue-Sun 11am-2am. Phone: 303-296-3352. Email: theretroroom@hotmail.com. Known as 'home of the original pickle shot.' Sources conflict slightly on prices: their own Squarespace site says $4 You-Call-Its and $7 Burger & Beer; milehighhappyhour.com says $3 U-Call-Its and $6 Burger & Beer. The restaurant's own website is likely more current. Also features infused vodkas (honey habanero, pepperoncini, root beer, pickle). Connected to Retro Room Salon. Opened in 2008. Instagram: @retroroomdenver."
+ },
+ {
+ "id": "reivers-bar-grill",
+ "name": "Reiver's Bar & Grill",
+ "source": "https://ultimatehappyhours.com/restaurants/reivers-bar-grill/, https://reiversbarandgrill.com/happy-hour/",
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "2:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$8 chips, guac & salsa",
+ "$8 black bean dip",
+ "$9 Greek style fried cheese",
+ "$10 hot honey shrimp",
+ "$10 deviled eggs",
+ "$11 Mexican street corn & Brussels",
+ "$11 Greek style hummus",
+ "$12 homemade pickle chips",
+ "$12 prime rib egg rolls",
+ "$13 short rib nachos",
+ "$13 pretzels & queso"
+ ],
+ "drink_deals": [
+ "$1 off draft beers",
+ "$6 house wine",
+ "$8 cocktails",
+ "$3.75 Avery IPA (14oz)",
+ "$6.50 Avery IPA (25oz)",
+ "$15 Avery IPA (60oz pitcher)"
+ ],
+ "notes": "Located at 1085 S Gaylord St, Denver, CO 80209 (Washington Park / Old Gaylord Street Shops). Open since 1977. Mon-Thu 11am-10pm, Fri 11am-11pm, Sat 10am-11pm, Sun 10am-10pm. Phone: (303) 733-8856. Menu last updated 06/22/2025. Part of Vibe Concepts. Note: reiversbarandgrill.com/happy-hour returned 403 Forbidden during direct crawling, but data was successfully retrieved from ultimatehappyhours.com (updated June 2025) and web search results."
+ }
+]
diff --git a/denver-happy-hours/data/extra-lodo.json b/denver-happy-hours/data/extra-lodo.json
new file mode 100644
index 00000000..4b7c0d32
--- /dev/null
+++ b/denver-happy-hours/data/extra-lodo.json
@@ -0,0 +1,226 @@
+[
+ {
+ "id": "jax-fish-house",
+ "name": "Jax Fish House & Oyster Bar",
+ "address": "1539 17th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.jaxfishhouse.com/location/jax-fish-house-oyster-bar-lodo/",
+ "source": "jaxfishhouse.com happy hour menu page, milehighhappyhour.com, 5280.com",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "CrackerJax Oysters $2 each",
+ "West Coast Oyster $3 each",
+ "Chargrilled Oyster $5 each",
+ "French Fries $6",
+ "Hush Puppies $7",
+ "Cup of Gumbo $8",
+ "Fish House Chopped Salad $8",
+ "Peel N' Eat Shrimp 1/4 LB $10",
+ "Grilled Shishitos $11",
+ "Steamed PEI Mussels 1/2 LB $12",
+ "Lobster & Shrimp Deviled Eggs $4 single / $12 for 3",
+ "Fried New England Calamari $13",
+ "Chile Lime Fish Tostadas $13",
+ "Gumbo Fries $13",
+ "Jax Fish Sandwich $14",
+ "The Lure Sampler $41"
+ ],
+ "drink_deals": [
+ "Odell Lager (can) $5",
+ "Draft Beer $1 off",
+ "Oyster Shooter $8",
+ "Whiskey Tea $10",
+ "On Tap Cocktail $10",
+ "Jax Strawberry Lemonade $10",
+ "Cucumber Lemon Press $10",
+ "Jax Rickey $10",
+ "Vita Vivet Cava (glass) $11",
+ "Chateau de Sancerre (glass) $11",
+ "Reguta Chardonnay (glass) $11",
+ "Poggio Terra Barbera (glass) $11",
+ "Jack Rabbit Hill Martini $12"
+ ]
+ },
+ "notes": "All-night happy hour on Mondays. Tue-Sun happy hour is 3:00-5:00 PM. Serving Denver's best seafood since 1996. Lines form before opening for the oyster deals. Hours: Mon-Thu 3-9 PM, Fri-Sat 3-10 PM, Sun 3-9 PM."
+ },
+ {
+ "id": "tavernetta",
+ "name": "Tavernetta",
+ "address": "1889 16th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.tavernettadenver.com/",
+ "source": "tavernettadenver.com happy hour menu page, 5280.com, milehighhappyhour.com",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Alici (Anchovy, Tomato, Oregano) $5",
+ "Marcona Almond (Lavender, Fennel) $6",
+ "Focaccia (Olive Oil, Red Wine Vinegar, Grana Padano) $7",
+ "Marinated Olives (Coriander, Citrus, Calabrian Chili) $7",
+ "Polpette (Beef & Pork Meatballs, Pomodoro, Grana Padano) $8",
+ "Parmigiano Reggiano e Balsamico $10",
+ "Gorgonzola e Miele $10",
+ "Bocconcino E Frutta $10",
+ "Carrozza (Mozzarella di Bufala, Trapanese Pesto) $10",
+ "Prosciutto di Parma $12",
+ "Salame Finocchiona $12",
+ "Coppa $12",
+ "Cacio e Pepe (Pecorino Romano, Black Pepper) $15",
+ "Insalata Mista $18",
+ "Calamari Fritti $19",
+ "Burrata $21",
+ "Bucatini all'Amatriciana $22",
+ "Roman Pasta Flight $45"
+ ],
+ "drink_deals": [
+ "Peroni $8",
+ "Scarpetta Frico Bianco (wine) $9",
+ "Scarpetta Frico Rosso (wine) $9",
+ "Scarpetta Frico Rosato (wine) $9",
+ "Venetian Spritz $9",
+ "Elena Spritz $14",
+ "Penicillin $14",
+ "Jungle Bird $14",
+ "Late For The Train $14",
+ "Old Fashioned $16"
+ ]
+ },
+ "notes": "Northern Italian eatery located just off the Union Station train platform. MICHELIN Bib Gourmand (2023 and 2024). Happy hour is bar and lounge area only. Dinner menu available starting at 5 PM for happy hour reservations (2-hour dining window for parties up to 4)."
+ },
+ {
+ "id": "cholon-modern-asian",
+ "name": "ChoLon Modern Asian",
+ "address": "1555 Blake St, Ste 101, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.cholonconcepts.com/locations/cholon-downtown/",
+ "source": "cholonconcepts.com happy hour menu page, milehighhappyhour.com, 5280.com",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "French Onion Soup Dumplings (2) $6",
+ "General Cho's Soup Dumplings (2) $6",
+ "Kaya Toast $6",
+ "Jumbo Shrimp Satay (2) $6",
+ "Chiang Mai Chicken Wontons (2) $6",
+ "Crispy Chicken Spring Rolls (2) $6",
+ "Korean Hot Fried Chicken Slider (1) $6",
+ "Pork Potstickers (2) $6",
+ "Cha Ca La Shrimp Cake Bao Bun (1) $6",
+ "Pork Belly or Tofu Bao Bun (1) $6",
+ "Scallion Pancake $6",
+ "French Fries $6",
+ "5 Spice Doughnuts (2) $6",
+ "Flights & Bites combo (3 dim sum/small bites + 1 sake flight) $33"
+ ],
+ "drink_deals": [
+ "Lon's Lager $5",
+ "Bushido Sake $6",
+ "House Wine $7",
+ "Well Drinks $7",
+ "Sparkling Brut Rose $8 glass / $38 bottle",
+ "Prosecco $8 glass / $38 bottle",
+ "ChoLon Cocktails $3 off",
+ "Seasonal Cocktail (Bartender's Choice) $10"
+ ]
+ },
+ "notes": "Closed Sundays. Upscale Asian fusion on the corner of 16th St Mall and Blake St. Has been a LoDo staple for over a decade. Phone: (303) 353-5223. Rated 4.7 stars on OpenTable."
+ },
+ {
+ "id": "hayters-and-co",
+ "name": "Hayter's & Co",
+ "address": "1920 Blake St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.haytersandco.com/",
+ "source": "milehighhappyhour.com/lower-downtown/hayters-co/, haytersandco.com specials page",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "11:00 AM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Monday: $9.99 all-you-can-eat wings (7pm-close)"
+ ],
+ "drink_deals": [
+ "$3 Drafts",
+ "$3 Wells",
+ "$4 Hayterade (Svedka citron, Svedka raspberry, lemonade, cranberry splash)",
+ "Tuesday: $3 Calls",
+ "Wednesday: $5 specialty Colorado vodka, $4 Fireball (7pm-close)",
+ "Thursday: Ladies night 9pm-close with complimentary wells",
+ "Friday: $5 Fireball, $5 Rum Chata",
+ "Saturday: $5 Fireball, $5 Rum Chata",
+ "Sunday: $3 Jager, $3 Jameson, $3 Tuaca, $3 Rumple Minze"
+ ]
+ },
+ "notes": "Sports bar across from Coors Field. $10 all-you-can-drink Coors Light before Rockies home games. Features beer pong, skeeball, Jenga, multiple TVs. Denver home bar for Chicago Bears, Montana State Bobcats, Montana Grizzlies, Ohio State Buckeyes. Hours: Mon-Wed 4pm-1:45am, Thu 12pm-1:45am, Fri-Sun 11am-1:45am."
+ },
+ {
+ "id": "thirsty-lion",
+ "name": "Thirsty Lion Gastropub & Grill",
+ "address": "1605 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.thirstylionrestaurant.com/",
+ "source": "thirstylionrestaurant.com happy hour page, milehighhappyhour.com",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Creamy Queso Dip $8.95",
+ "Garlic Sesame Edamame $8.95",
+ "Fresh Hand Cut Fries $8.95",
+ "Beer Battered Cheese Curds $8.95",
+ "Artichoke Spinach Dip $9.95",
+ "Spicy Fried Cauliflower $9.95",
+ "Hand-Breaded Chicken Tenderloins $9.95",
+ "California Roll $9.95",
+ "Spicy Tuna Roll $9.95",
+ "Ahi Poke Stack $10.95",
+ "Pear & Prosciutto Flatbread $10.95",
+ "Spicy Fried Chicken Sliders $10.95",
+ "Grilled Burger Sliders $10.95",
+ "Grilled Salmon Cakes $10.95"
+ ],
+ "drink_deals": [
+ "Lion Lemonade $8.95",
+ "Ranch Water $8.95",
+ "Hibiscus Vodka Breeze $8.95",
+ "Moscow Mule $9.95",
+ "Thirsty Lion Margarita $9.95",
+ "Spicy Mango Margarita $9.95",
+ "Classic Mojito $9.95",
+ "Cucumber Rosemary Gin & Tonic $9.95",
+ "Blood Orange Margarita $9.95",
+ "Bourbon Old Fashioned $9.95",
+ "Raspberry Drop Martini $9.95"
+ ]
+ },
+ "notes": "Located in Union Station. Also has late night happy hour Thu-Sat 9pm-close. Weekend brunch Sat-Sun 10am-2pm with $25 mimosa bottles. Prices noted on their website as potentially varying at the Denver location. Rated 4.5 stars on OpenTable."
+ },
+ {
+ "id": "hopdoddy-burger-bar",
+ "name": "Hopdoddy Burger Bar",
+ "address": "1747 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.hopdoddy.com/locations/unionstation",
+ "source": "hopdoddy.com, milehighhappyhour.com, do303.com",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "1/2 off all cocktails",
+ "1/2 off all beer",
+ "1/2 off all wine"
+ ]
+ },
+ "notes": "Located between Union Station and Coors Field. Happy hour is Mon-Thu only, 3-6 PM with half off all cocktails, beer, and wine. Known for craft burgers and an impressive cocktail/wine program. Hours: Mon-Thu 11am-10pm, Fri-Sat 11am-11pm, Sun 11am-10pm. Phone: (303) 446-2337. Could not fetch their happy hour page directly for food deal specifics."
+ }
+]
diff --git a/denver-happy-hours/data/extra-lohi.json b/denver-happy-hours/data/extra-lohi.json
new file mode 100644
index 00000000..eb91d676
--- /dev/null
+++ b/denver-happy-hours/data/extra-lohi.json
@@ -0,0 +1,170 @@
+[
+ {
+ "id": "postino-lohi",
+ "name": "Postino LoHi",
+ "address": "2715 17th St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.postino.com/locations/postino-lohi",
+ "source": "postino.com, ultimatehappyhours.com/restaurants/postino-lohi",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "Open",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "$25 board of bruschetta + bottle of wine (Monday & Tuesday after 8 PM only)"
+ ],
+ "drink_deals": [
+ "$6 glass of wine (any bottle on the menu)",
+ "$6 pitcher of beer"
+ ]
+ },
+ "notes": "Happy hour runs from open until 5 PM daily (Mon-Thu open at 11 AM, Fri 11 AM, Sat-Sun 10 AM). Monday and Tuesday after 8 PM there is a separate late-night deal: bruschetta board + bottle of wine for $25. Very popular; pet-friendly patio."
+ },
+ {
+ "id": "cart-driver-lohi",
+ "name": "Cart-Driver LoHi",
+ "address": "2239 W 30th Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.cart-driver.com/lohi",
+ "source": "cart-driver.com, diningout.com/denver/happy-hour-cart-driver-pizza-denver",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "4:00 PM (Mon-Thu) / 3:00 PM (Fri-Sun)",
+ "end_time": "6:00 PM (Mon-Thu) / 5:00 PM (Fri-Sun)",
+ "food_deals": [
+ "Daisy pizza $10 (normally $18)",
+ "Oysters $3.50 each",
+ "Chicken liver mousse with rosemary focaccia $9",
+ "Mini board (sardines, piada bread, compound butter, sambal) $10"
+ ],
+ "drink_deals": [
+ "Prosecco on tap $8/glass",
+ "House red or white wine $9/pour",
+ "Messed Up Negroni (gin, vermouth, Campari, prosecco) $8",
+ "Bartender's choice cocktail $8",
+ "Genesee tall boy $3.50"
+ ]
+ },
+ "notes": "Reopened January 2025 after extended closure for plumbing repairs. Known for wood-fired pizza, fresh oysters, and house-made pasta. Dine-in only for happy hour. Reservations recommended as it fills up fast. Mon 4-9pm, Tue-Sat 4-10pm, Sun 4-9pm."
+ },
+ {
+ "id": "bar-dough",
+ "name": "Bar Dough",
+ "address": "2227 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.bardoughdenver.com",
+ "source": "bardoughdenver.com/menu/happy-hour, milehighhappyhour.com/highlands/bar-dough",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "Castelvetrano Olives $6",
+ "Fried Ravioli $8",
+ "Charcuterie Plate $10",
+ "3x Cheese Pizza $10 (add pepperoni, sausage, or prosciutto +$2)",
+ "Meatball Sub $13",
+ "Cacio E Pepe $15",
+ "Verde Salad $10"
+ ],
+ "drink_deals": [
+ "Montucky Lager $5",
+ "House Wine (red or white) $7",
+ "Old Fashioned $8",
+ "Plum Margarita $8",
+ "Aperol Spritz $8",
+ "Grappa Sour $11",
+ "Limoncello Flight $12",
+ "Espresso-Tini Flight $14"
+ ]
+ },
+ "notes": "Prices sourced from official website happy hour menu page (bardoughdenver.com/menu/happy-hour). Note: milehighhappyhour.com lists lower legacy prices ($5 food items, $5-7 drinks) and Mon-Fri 3-5:30 PM hours -- the official site is likely more current. Modern regional Italian cuisine with wood-fired pizza. Phone: (720) 668-8506."
+ },
+ {
+ "id": "root-down",
+ "name": "Root Down",
+ "address": "1600 W 33rd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://ediblebeats.com/restaurants/root-down/",
+ "source": "milehighhappyhour.com/highlands/root-down, ediblebeats.com",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "4:30 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [
+ "Spring Vegetable Fritto Misto $5",
+ "Steamed PEI Mussels $7",
+ "Seared Colombian Arepas $4.50",
+ "Edamame Hummus $4",
+ "Shrimp Cocktail $7",
+ "Organic Sweet Potato Fries $4",
+ "Veggie Burger Slider $4",
+ "Green Chili Duck Taco $4",
+ "Colorado Lamb Slider $5"
+ ],
+ "drink_deals": [
+ "$5 Cocktails: Cucumber Daisy, South Side, Coconut Ginger Caipirinha, Spicy Paloma, Don Draper",
+ "$5 House Red or White Wine",
+ "$4 Selected Draft",
+ "$3 Cold Ozeki Kara Dry Sake",
+ "$2 PBR or Miller High Life"
+ ]
+ },
+ "notes": "Food items are seasonal and rotate; the items listed were sourced from milehighhappyhour.com and may have changed. Sister restaurant of Linger (same owner, Edible Beats). Farm-to-table focus with sustainable sourcing. Also offers an Early Bird 3-course menu for $38 Mon-Thu 4:30-6 PM. Phone: (303) 993-4200."
+ },
+ {
+ "id": "ashkara",
+ "name": "Ash'Kara",
+ "address": "2005 W 33rd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.ashkaradenver.com",
+ "source": "ashkaradenver.com/menus, OpenTable, denverinsider.org",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Pickles (cucumber, carrot, beet) $7",
+ "Castelvetrano Olives (Calabrian chili, orange) $5",
+ "Fried Halloumi and Panisse $7",
+ "Hummus $10",
+ "Carrot Kibbeh Nayyeh (ground carrot tartare, apricot, sunflower seeds) $10",
+ "Mezze Trio (htipiti, whipped labneh, babaganoush) $13",
+ "Chicken Kebab $6",
+ "Lamb or Steak Kebab $8",
+ "Za'atar Spiced Fries with harissa aioli $5"
+ ],
+ "drink_deals": [
+ "Draft Beer (Ratio selections) $5",
+ "House Wine (red, white, rosé, sparkling) $8",
+ "Mediterranean V&T $9",
+ "Berry Bourbon Smash $9",
+ "Aperol Spritz $10",
+ "AK Old-Fashioned (bourbon, vanilla, cherry, cardamom) $15"
+ ]
+ },
+ "notes": "Three-time Michelin Bib Gourmand winner (2023-2025). Named 5280 Magazine's Best Mediterranean Restaurant 2025. Full happy hour 3-5 PM, bar-only extension 5-6 PM. Wood-fired oven bakes pita to order. Middle Eastern / Mediterranean cuisine by Chef Reginald Dotson. Phone: (303) 537-4407."
+ },
+ {
+ "id": "highland-tavern",
+ "name": "Highland Tavern",
+ "address": "3400 Navajo St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://highlandtavern.com",
+ "source": "milehighhappyhour.com/highlands/highland-tavern, totalhappyhour.com, yelp.com",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "4:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$3 Bud, Coors, or Miller bottles",
+ "$2 PBR",
+ "$4 Well drinks",
+ "$4.50 House Wine by the glass",
+ "$1 off select draft beers"
+ ]
+ },
+ "notes": "Also has late-night specials daily 9 PM to close. Featured on Food Network's Diners, Drive-Ins and Dives. Known for homemade tater tots, buffalo wings, chicharones, and K-town Rib Tips. Neighborhood corner pub since 2006 with pool table, ping-pong, foosball, video games, and free Wi-Fi. Food happy hour deals not confirmed -- call (303) 433-1990 to verify. Open Mon-Fri 11 AM-2 AM, Sat-Sun 10 AM-2 AM."
+ }
+]
diff --git a/denver-happy-hours/data/happy_hours.json b/denver-happy-hours/data/happy_hours.json
new file mode 100644
index 00000000..1e771e43
--- /dev/null
+++ b/denver-happy-hours/data/happy_hours.json
@@ -0,0 +1,842 @@
+[
+ {
+ "id": "cholon-modern-asian",
+ "name": "ChoLon Modern Asian",
+ "address": "1555 Blake St, Ste 101, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.cholonconcepts.com/locations/cholon-downtown/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "French Onion Soup Dumplings (2) $6",
+ "General Cho's Soup Dumplings (2) $6",
+ "Kaya Toast $6",
+ "Jumbo Shrimp Satay (2) $6",
+ "Chiang Mai Chicken Wontons (2) $6",
+ "Crispy Chicken Spring Rolls (2) $6",
+ "Korean Hot Fried Chicken Slider (1) $6",
+ "Pork Potstickers (2) $6",
+ "Cha Ca La Shrimp Cake Bao Bun (1) $6",
+ "Pork Belly or Tofu Bao Bun (1) $6",
+ "Scallion Pancake $6",
+ "French Fries $6",
+ "5 Spice Doughnuts (2) $6",
+ "Flights & Bites combo (3 dim sum/small bites + 1 sake flight) $33"
+ ],
+ "drink_deals": [
+ "Lon's Lager $5",
+ "Bushido Sake $6",
+ "House Wine $7",
+ "Well Drinks $7",
+ "Sparkling Brut Rose $8 glass / $38 bottle",
+ "Prosecco $8 glass / $38 bottle",
+ "ChoLon Cocktails $3 off",
+ "Seasonal Cocktail (Bartender's Choice) $10"
+ ]
+ }
+ },
+ {
+ "id": "hayters-and-co",
+ "name": "Hayter's & Co",
+ "address": "1920 Blake St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.haytersandco.com/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "11:00 AM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Monday: $9.99 all-you-can-eat wings (7pm-close)"
+ ],
+ "drink_deals": [
+ "$3 Drafts",
+ "$3 Wells",
+ "$4 Hayterade (Svedka citron, Svedka raspberry, lemonade, cranberry splash)",
+ "Tuesday: $3 Calls",
+ "Wednesday: $5 specialty Colorado vodka, $4 Fireball (7pm-close)",
+ "Thursday: Ladies night 9pm-close with complimentary wells",
+ "Friday: $5 Fireball, $5 Rum Chata",
+ "Saturday: $5 Fireball, $5 Rum Chata",
+ "Sunday: $3 Jager, $3 Jameson, $3 Tuaca, $3 Rumple Minze"
+ ]
+ }
+ },
+ {
+ "id": "herbs-hideout",
+ "name": "Herb's Hideout",
+ "address": "2057 Larimer St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "http://www.herbsbar.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [
+ "$2 Tacos (Monday)",
+ "1/2 priced appetizers"
+ ],
+ "drink_deals": [
+ "$3 wells & domestic pints",
+ "$4 You Call It (top shelf excluded)",
+ "$2 Coors Light drafts",
+ "$5 daily shot specials"
+ ]
+ }
+ },
+ {
+ "id": "hopdoddy-burger-bar",
+ "name": "Hopdoddy Burger Bar",
+ "address": "1747 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.hopdoddy.com/locations/unionstation",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "1/2 off all cocktails",
+ "1/2 off all beer",
+ "1/2 off all wine"
+ ]
+ }
+ },
+ {
+ "id": "jax-fish-house",
+ "name": "Jax Fish House & Oyster Bar",
+ "address": "1539 17th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.jaxfishhouse.com/location/jax-fish-house-oyster-bar-lodo/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "CrackerJax Oysters $2 each",
+ "West Coast Oyster $3 each",
+ "Chargrilled Oyster $5 each",
+ "French Fries $6",
+ "Hush Puppies $7",
+ "Cup of Gumbo $8",
+ "Fish House Chopped Salad $8",
+ "Peel N' Eat Shrimp 1/4 LB $10",
+ "Grilled Shishitos $11",
+ "Steamed PEI Mussels 1/2 LB $12",
+ "Lobster & Shrimp Deviled Eggs $4 single / $12 for 3",
+ "Fried New England Calamari $13",
+ "Chile Lime Fish Tostadas $13",
+ "Gumbo Fries $13",
+ "Jax Fish Sandwich $14",
+ "The Lure Sampler $41"
+ ],
+ "drink_deals": [
+ "Odell Lager (can) $5",
+ "Draft Beer $1 off",
+ "Oyster Shooter $8",
+ "Whiskey Tea $10",
+ "On Tap Cocktail $10",
+ "Jax Strawberry Lemonade $10",
+ "Cucumber Lemon Press $10",
+ "Jax Rickey $10",
+ "Vita Vivet Cava (glass) $11",
+ "Chateau de Sancerre (glass) $11",
+ "Reguta Chardonnay (glass) $11",
+ "Poggio Terra Barbera (glass) $11",
+ "Jack Rabbit Hill Martini $12"
+ ]
+ }
+ },
+ {
+ "id": "nallens-irish-pub",
+ "name": "Nallen's Irish Pub",
+ "address": "1429 Market St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": null,
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "2:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [],
+ "drink_deals": [
+ "$1 off all drinks",
+ "$3 Bud Light Drafts",
+ "$4 Carbombs"
+ ]
+ }
+ },
+ {
+ "id": "poka-lola-social-club",
+ "name": "Poka Lola Social Club",
+ "address": "1850 Wazee St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.pokaloladenver.com/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "Discounted craft cocktails",
+ "Discounted house-made sodas and cocktails"
+ ]
+ }
+ },
+ {
+ "id": "seven-grand",
+ "name": "Seven Grand",
+ "address": "1855 Blake St, Suite 160, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.sevengrandbars.com/denver",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$6 happy hour cocktails",
+ "Discounted whiskey selections from 700+ bottle collection"
+ ]
+ }
+ },
+ {
+ "id": "tavernetta",
+ "name": "Tavernetta",
+ "address": "1889 16th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.tavernettadenver.com/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Alici",
+ "$6 Marcona Almonds",
+ "$7 Focaccia",
+ "$7 Marinated Olives",
+ "$8 Polpette",
+ "$10 Parmigiano Reggiano e Balsamico",
+ "$10 Gorgonzola e Miele",
+ "$10 Bocconcino e Frutta",
+ "$10 Carrozza",
+ "$12 Prosciutto di Parma",
+ "$12 Salame Finocchiona",
+ "$12 Coppa",
+ "$15 Cacio e Pepe",
+ "$18 Insalata Mista",
+ "$19 Calamari Fritti",
+ "$21 Burrata",
+ "$22 Bucatini all'Amatriciana",
+ "$45 Roman Pasta Flight"
+ ],
+ "drink_deals": [
+ "$8 Peroni draft",
+ "$9 Scarpetta Frico wines (Bianco, Rosso, Rosato)",
+ "$9 Venetian Spritz",
+ "$14 Elena Spritz",
+ "$14 Penicillin cocktail",
+ "$14 Jungle Bird cocktail",
+ "$14 Late For The Train cocktail",
+ "$16 Old Fashioned"
+ ]
+ }
+ },
+ {
+ "id": "terminal-bar",
+ "name": "Terminal Bar",
+ "address": "1701 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://terminalbardenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$5.50 select draught beer",
+ "$7 well spirits",
+ "$7.50 house wines"
+ ]
+ }
+ },
+ {
+ "id": "the-1up-lodo",
+ "name": "The 1UP Arcade Bar - LoDo",
+ "address": "1925 Blake St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://the1uparcadebar.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$2 Coors Light Draft",
+ "$3 Pickle Shots",
+ "$3 well liquor",
+ "$5 Jack Daniel's / Tito's / Herradura",
+ "$6 1UP IPA Drafts",
+ "$1 off all cans"
+ ]
+ }
+ },
+ {
+ "id": "the-cruise-room",
+ "name": "The Cruise Room",
+ "address": "1600 17th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.theoxfordhotel.com/eat-drink/the-cruise-room",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "5:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "Captain's Call \u2014 bartender's choice cocktail"
+ ]
+ }
+ },
+ {
+ "id": "thirsty-lion",
+ "name": "Thirsty Lion Gastropub & Grill",
+ "address": "1605 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.thirstylionrestaurant.com/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Creamy Queso Dip $8.95",
+ "Garlic Sesame Edamame $8.95",
+ "Fresh Hand Cut Fries $8.95",
+ "Beer Battered Cheese Curds $8.95",
+ "Artichoke Spinach Dip $9.95",
+ "Spicy Fried Cauliflower $9.95",
+ "Hand-Breaded Chicken Tenderloins $9.95",
+ "California Roll $9.95",
+ "Spicy Tuna Roll $9.95",
+ "Ahi Poke Stack $10.95",
+ "Pear & Prosciutto Flatbread $10.95",
+ "Spicy Fried Chicken Sliders $10.95",
+ "Grilled Burger Sliders $10.95",
+ "Grilled Salmon Cakes $10.95"
+ ],
+ "drink_deals": [
+ "Lion Lemonade $8.95",
+ "Ranch Water $8.95",
+ "Hibiscus Vodka Breeze $8.95",
+ "Moscow Mule $9.95",
+ "Thirsty Lion Margarita $9.95",
+ "Spicy Mango Margarita $9.95",
+ "Classic Mojito $9.95",
+ "Cucumber Rosemary Gin & Tonic $9.95",
+ "Blood Orange Margarita $9.95",
+ "Bourbon Old Fashioned $9.95",
+ "Raspberry Drop Martini $9.95"
+ ]
+ }
+ },
+ {
+ "id": "viewhouse-ballpark",
+ "name": "ViewHouse Eatery, Bar & Rooftop",
+ "address": "2015 Market St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "https://www.viewhouse.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Sweet Potato Fries",
+ "$5 Chips and Salsa",
+ "$7 Bee Sting Cauliflower",
+ "$7 Pork Green Chili"
+ ],
+ "drink_deals": [
+ "$4 Bud/Coors Light",
+ "$4 well gin/rum/vodka/whiskey",
+ "$6 craft drafts",
+ "$8 signature cocktails (margaritas, mules, palomas)"
+ ]
+ }
+ },
+ {
+ "id": "wynkoop-brewing-company",
+ "name": "Wynkoop Brewing Company",
+ "address": "1634 18th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://wynkoop.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Pulled Chicken Tacos (roasted corn pico, cotija, cilantro)",
+ "Food specials starting at $5"
+ ],
+ "drink_deals": [
+ "$2 off all Wynkoop beers",
+ "$2 off house wines",
+ "$2 off well drinks"
+ ]
+ }
+ },
+ {
+ "id": "ashkara",
+ "name": "Ash'Kara",
+ "address": "2005 W 33rd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.ashkaradenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Pickles (cucumber, carrot, beet) $7",
+ "Castelvetrano Olives (Calabrian chili, orange) $5",
+ "Fried Halloumi and Panisse $7",
+ "Hummus $10",
+ "Carrot Kibbeh Nayyeh (ground carrot tartare, apricot, sunflower seeds) $10",
+ "Mezze Trio (htipiti, whipped labneh, babaganoush) $13",
+ "Chicken Kebab $6",
+ "Lamb or Steak Kebab $8",
+ "Za'atar Spiced Fries with harissa aioli $5"
+ ],
+ "drink_deals": [
+ "Draft Beer (Ratio selections) $5",
+ "House Wine (red, white, ros\u00e9, sparkling) $8",
+ "Mediterranean V&T $9",
+ "Berry Bourbon Smash $9",
+ "Aperol Spritz $10",
+ "AK Old-Fashioned (bourbon, vanilla, cherry, cardamom) $15"
+ ]
+ }
+ },
+ {
+ "id": "avanti-food-beverage",
+ "name": "Avanti Food & Beverage",
+ "address": "3200 Pecos St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.avantifandb.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "2:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$4 Upslope Snowmelt Seltzer",
+ "$5 Odell Lagerado",
+ "$6 Avery IPA",
+ "$6 house wine",
+ "$6 house spirits",
+ "$7 Jack Daniel's"
+ ]
+ }
+ },
+ {
+ "id": "bar-dough",
+ "name": "Bar Dough",
+ "address": "2227 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.bardoughdenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "Castelvetrano Olives $6",
+ "Fried Ravioli $8",
+ "Charcuterie Plate $10",
+ "3x Cheese Pizza $10 (add pepperoni, sausage, or prosciutto +$2)",
+ "Meatball Sub $13",
+ "Cacio E Pepe $15",
+ "Verde Salad $10"
+ ],
+ "drink_deals": [
+ "Montucky Lager $5",
+ "House Wine (red or white) $7",
+ "Old Fashioned $8",
+ "Plum Margarita $8",
+ "Aperol Spritz $8",
+ "Grappa Sour $11",
+ "Limoncello Flight $12",
+ "Espresso-Tini Flight $14"
+ ]
+ }
+ },
+ {
+ "id": "cart-driver-lohi",
+ "name": "Cart-Driver LoHi",
+ "address": "2239 W 30th Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.cart-driver.com/lohi",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Daisy pizza $10 (normally $18)",
+ "Oysters $3.50 each",
+ "Chicken liver mousse with rosemary focaccia $9",
+ "Mini board (sardines, piada bread, compound butter, sambal) $10"
+ ],
+ "drink_deals": [
+ "Prosecco on tap $8/glass",
+ "House red or white wine $9/pour",
+ "Messed Up Negroni (gin, vermouth, Campari, prosecco) $8",
+ "Bartender's choice cocktail $8",
+ "Genesee tall boy $3.50"
+ ]
+ }
+ },
+ {
+ "id": "el-camino-community-tavern",
+ "name": "El Camino Community Tavern",
+ "address": "3628 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://elcaminotavern.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "$8 Green chili nachos",
+ "$6 Shishito peppers",
+ "$7 Mini guac & chili con queso"
+ ],
+ "drink_deals": [
+ "$2 Tecate",
+ "$5 ALE camino",
+ "$6 El Camino margarita",
+ "$7 Deer-&-beer (Imperial + Cazadores shot)",
+ "$6 wine by the glass"
+ ]
+ }
+ },
+ {
+ "id": "highland-tap-and-burger",
+ "name": "Highland Tap and Burger",
+ "address": "2219 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://tapandburger.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$4 Hand Cut Fries w/ truffled aioli",
+ "$5 Chili Cheese Fries",
+ "$5 Steak Tacos (2)",
+ "$5 Sliders (choose 2)"
+ ],
+ "drink_deals": [
+ "$3 select draft beers",
+ "1/2 off bottles of house wine",
+ "$5 Moscow Mules / Dark 'n Stormy / Coin Margarita",
+ "$5 Jameson Irish Whiskey"
+ ]
+ }
+ },
+ {
+ "id": "highland-tavern",
+ "name": "Highland Tavern",
+ "address": "3400 Navajo St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://highlandtavern.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$3 Bud, Coors, or Miller bottles",
+ "$2 PBR",
+ "$4 Well drinks",
+ "$4.50 House Wine by the glass",
+ "$1 off select draft beers"
+ ]
+ }
+ },
+ {
+ "id": "linger",
+ "name": "Linger",
+ "address": "2030 W 30th Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://lingerdenver.com",
+ "happy_hour": {
+ "days": [
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$7 French onion mussels",
+ "$5.50 Wagyu slider",
+ "$4 Mongolian BBQ duck bun",
+ "$5 Sweet potato waffle fries",
+ "$3.50 Jerk chicken lettuce wrap"
+ ],
+ "drink_deals": [
+ "$4 select draft beer",
+ "$5 house wine",
+ "$5 Red sangria",
+ "$5 cocktails (Ginger collins, Coconut daiquiri, Whiskey daisy)"
+ ]
+ }
+ },
+ {
+ "id": "postino-lohi",
+ "name": "Postino LoHi",
+ "address": "2715 17th St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.postinowinecafe.com/locations/postino-lohi",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "11:00 AM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "$25 bruschetta board + bottle of wine (Mon & Tue after 8 PM)"
+ ],
+ "drink_deals": [
+ "$6 glasses of wine (all day until 5 PM)",
+ "$6 pitchers of beer (all day until 5 PM)"
+ ]
+ }
+ },
+ {
+ "id": "root-down",
+ "name": "Root Down",
+ "address": "1600 W 33rd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://ediblebeats.com/restaurants/root-down/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "4:30 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [
+ "Spring Vegetable Fritto Misto $5",
+ "Steamed PEI Mussels $7",
+ "Seared Colombian Arepas $4.50",
+ "Edamame Hummus $4",
+ "Shrimp Cocktail $7",
+ "Organic Sweet Potato Fries $4",
+ "Veggie Burger Slider $4",
+ "Green Chili Duck Taco $4",
+ "Colorado Lamb Slider $5"
+ ],
+ "drink_deals": [
+ "$5 Cocktails: Cucumber Daisy, South Side, Coconut Ginger Caipirinha, Spicy Paloma, Don Draper",
+ "$5 House Red or White Wine",
+ "$4 Selected Draft",
+ "$3 Cold Ozeki Kara Dry Sake",
+ "$2 PBR or Miller High Life"
+ ]
+ }
+ },
+ {
+ "id": "senor-bear",
+ "name": "Se\u00f1or Bear",
+ "address": "3301 Tejon St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://senorbeardenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$1.25 chicken wing confit (each)",
+ "$3.50 Gordo Crunch",
+ "$4 Mezcla de Fiesta (snack mix)",
+ "$4.50 Latin Pizza",
+ "$5.50 Seafood tostada"
+ ],
+ "drink_deals": [
+ "$3 Tecate",
+ "$4 Michelada",
+ "$5 Margarita / Paloma / Pisco sour",
+ "$5 daily wine (red or white)"
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/denver-happy-hours/data/raw/ale-house-at-amato-s.txt b/denver-happy-hours/data/raw/ale-house-at-amato-s.txt
new file mode 100644
index 00000000..97074560
--- /dev/null
+++ b/denver-happy-hours/data/raw/ale-house-at-amato-s.txt
@@ -0,0 +1,6 @@
+Venue: Ale House at Amato's
+Address: 2501 16th St, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://alehousedenver.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/avanti-food-beverage.txt b/denver-happy-hours/data/raw/avanti-food-beverage.txt
new file mode 100644
index 00000000..12466364
--- /dev/null
+++ b/denver-happy-hours/data/raw/avanti-food-beverage.txt
@@ -0,0 +1,6 @@
+Venue: Avanti Food & Beverage
+Address: 3200 Pecos St, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://avantifandb.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/el-camino-community-tavern.txt b/denver-happy-hours/data/raw/el-camino-community-tavern.txt
new file mode 100644
index 00000000..790a2548
--- /dev/null
+++ b/denver-happy-hours/data/raw/el-camino-community-tavern.txt
@@ -0,0 +1,6 @@
+Venue: El Camino Community Tavern
+Address: 3628 W 32nd Ave, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://elcaminotavern.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/falling-rock-tap-house.txt b/denver-happy-hours/data/raw/falling-rock-tap-house.txt
new file mode 100644
index 00000000..ed899421
--- /dev/null
+++ b/denver-happy-hours/data/raw/falling-rock-tap-house.txt
@@ -0,0 +1,6 @@
+Venue: Falling Rock Tap House
+Address: 1919 Blake St, Denver, CO 80202
+Neighborhood: LoDo
+Website: https://fallingrocktaphouse.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/garibaldi-mexican-bistro.txt b/denver-happy-hours/data/raw/garibaldi-mexican-bistro.txt
new file mode 100644
index 00000000..017b606c
--- /dev/null
+++ b/denver-happy-hours/data/raw/garibaldi-mexican-bistro.txt
@@ -0,0 +1,6 @@
+Venue: Garibaldi Mexican Bistro
+Address: 3055 Zuni St, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://garibaldimexican.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/great-divide-brewing.txt b/denver-happy-hours/data/raw/great-divide-brewing.txt
new file mode 100644
index 00000000..5b2cb302
--- /dev/null
+++ b/denver-happy-hours/data/raw/great-divide-brewing.txt
@@ -0,0 +1,6 @@
+Venue: Great Divide Brewing
+Address: 2201 Arapahoe St, Denver, CO 80205
+Neighborhood: LoDo
+Website: https://greatdivide.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/herb-s-hideout.txt b/denver-happy-hours/data/raw/herb-s-hideout.txt
new file mode 100644
index 00000000..212f90b8
--- /dev/null
+++ b/denver-happy-hours/data/raw/herb-s-hideout.txt
@@ -0,0 +1,6 @@
+Venue: Herb's Hideout
+Address: 2057 Larimer St, Denver, CO 80205
+Neighborhood: LoDo
+Website: https://herbshideout.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/highland-tap-and-burger.txt b/denver-happy-hours/data/raw/highland-tap-and-burger.txt
new file mode 100644
index 00000000..97a686cc
--- /dev/null
+++ b/denver-happy-hours/data/raw/highland-tap-and-burger.txt
@@ -0,0 +1,6 @@
+Venue: Highland Tap and Burger
+Address: 2219 W 32nd Ave, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://highlandtapandburger.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/jagged-mountain-craft-brewery.txt b/denver-happy-hours/data/raw/jagged-mountain-craft-brewery.txt
new file mode 100644
index 00000000..36397a4d
--- /dev/null
+++ b/denver-happy-hours/data/raw/jagged-mountain-craft-brewery.txt
@@ -0,0 +1,6 @@
+Venue: Jagged Mountain Craft Brewery
+Address: 1139 20th St, Denver, CO 80202
+Neighborhood: LoDo
+Website: https://jaggedmountainbrewery.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/linger.txt b/denver-happy-hours/data/raw/linger.txt
new file mode 100644
index 00000000..e2245c28
--- /dev/null
+++ b/denver-happy-hours/data/raw/linger.txt
@@ -0,0 +1,6 @@
+Venue: Linger
+Address: 2030 W 30th Ave, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://lingerdenver.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/little-man-ice-cream.txt b/denver-happy-hours/data/raw/little-man-ice-cream.txt
new file mode 100644
index 00000000..1ed0f59e
--- /dev/null
+++ b/denver-happy-hours/data/raw/little-man-ice-cream.txt
@@ -0,0 +1,6 @@
+Venue: Little Man Ice Cream
+Address: 2620 16th St, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://littlemanicecream.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/lohi-steakbar.txt b/denver-happy-hours/data/raw/lohi-steakbar.txt
new file mode 100644
index 00000000..9bcdb59a
--- /dev/null
+++ b/denver-happy-hours/data/raw/lohi-steakbar.txt
@@ -0,0 +1,6 @@
+Venue: LoHi SteakBar
+Address: 3200 Tejon St, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://lohisteakbar.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/nallen-s-irish-pub.txt b/denver-happy-hours/data/raw/nallen-s-irish-pub.txt
new file mode 100644
index 00000000..b2b3ee81
--- /dev/null
+++ b/denver-happy-hours/data/raw/nallen-s-irish-pub.txt
@@ -0,0 +1,6 @@
+Venue: Nallen's Irish Pub
+Address: 1429 Market St, Denver, CO 80202
+Neighborhood: LoDo
+Website: https://nallensirishpub.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/reiver-s-bar.txt b/denver-happy-hours/data/raw/reiver-s-bar.txt
new file mode 100644
index 00000000..e12f38f4
--- /dev/null
+++ b/denver-happy-hours/data/raw/reiver-s-bar.txt
@@ -0,0 +1,6 @@
+Venue: Reiver's Bar
+Address: 1085 S Gaylord St, Denver, CO 80209
+Neighborhood: LoHi
+Website: none
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/retro-room.txt b/denver-happy-hours/data/raw/retro-room.txt
new file mode 100644
index 00000000..a56e67ee
--- /dev/null
+++ b/denver-happy-hours/data/raw/retro-room.txt
@@ -0,0 +1,6 @@
+Venue: Retro Room
+Address: 1801 Wynkoop St, Denver, CO 80202
+Neighborhood: LoDo
+Website: none
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/se-or-bear.txt b/denver-happy-hours/data/raw/se-or-bear.txt
new file mode 100644
index 00000000..3e595ad1
--- /dev/null
+++ b/denver-happy-hours/data/raw/se-or-bear.txt
@@ -0,0 +1,6 @@
+Venue: Señor Bear
+Address: 3301 Tejon St, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://senorbeardenver.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/star-bar-denver.txt b/denver-happy-hours/data/raw/star-bar-denver.txt
new file mode 100644
index 00000000..51df5032
--- /dev/null
+++ b/denver-happy-hours/data/raw/star-bar-denver.txt
@@ -0,0 +1,6 @@
+Venue: Star Bar Denver
+Address: 2137 Larimer St, Denver, CO 80205
+Neighborhood: LoDo
+Website: https://starbardenver.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/terminal-bar.txt b/denver-happy-hours/data/raw/terminal-bar.txt
new file mode 100644
index 00000000..879b032d
--- /dev/null
+++ b/denver-happy-hours/data/raw/terminal-bar.txt
@@ -0,0 +1,6 @@
+Venue: Terminal Bar
+Address: 1701 Wynkoop St, Denver, CO 80202
+Neighborhood: LoDo
+Website: https://theterminalbar.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/the-1up-lodo.txt b/denver-happy-hours/data/raw/the-1up-lodo.txt
new file mode 100644
index 00000000..e4d51bf1
--- /dev/null
+++ b/denver-happy-hours/data/raw/the-1up-lodo.txt
@@ -0,0 +1,6 @@
+Venue: The 1UP - LoDo
+Address: 1925 Blake St, Denver, CO 80202
+Neighborhood: LoDo
+Website: https://the1up.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/the-cruise-room.txt b/denver-happy-hours/data/raw/the-cruise-room.txt
new file mode 100644
index 00000000..04bfa3f4
--- /dev/null
+++ b/denver-happy-hours/data/raw/the-cruise-room.txt
@@ -0,0 +1,6 @@
+Venue: The Cruise Room
+Address: 1600 17th St, Denver, CO 80202
+Neighborhood: LoDo
+Website: https://thecruiseroom.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/the-way-back.txt b/denver-happy-hours/data/raw/the-way-back.txt
new file mode 100644
index 00000000..475c802d
--- /dev/null
+++ b/denver-happy-hours/data/raw/the-way-back.txt
@@ -0,0 +1,6 @@
+Venue: The Way Back
+Address: 3279 Navajo St, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://thewaybackdenver.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/viewhouse-eatery.txt b/denver-happy-hours/data/raw/viewhouse-eatery.txt
new file mode 100644
index 00000000..7e1beee3
--- /dev/null
+++ b/denver-happy-hours/data/raw/viewhouse-eatery.txt
@@ -0,0 +1,6 @@
+Venue: Viewhouse Eatery
+Address: 2015 Market St, Denver, CO 80205
+Neighborhood: LoDo
+Website: https://viewhouse.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/williams-graham.txt b/denver-happy-hours/data/raw/williams-graham.txt
new file mode 100644
index 00000000..5e76fe06
--- /dev/null
+++ b/denver-happy-hours/data/raw/williams-graham.txt
@@ -0,0 +1,6 @@
+Venue: Williams & Graham
+Address: 3160 Tejon St, Denver, CO 80211
+Neighborhood: LoHi
+Website: https://williamsandgraham.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/raw/wynkoop-brewing-company.txt b/denver-happy-hours/data/raw/wynkoop-brewing-company.txt
new file mode 100644
index 00000000..aa38e71a
--- /dev/null
+++ b/denver-happy-hours/data/raw/wynkoop-brewing-company.txt
@@ -0,0 +1,6 @@
+Venue: Wynkoop Brewing Company
+Address: 1634 18th St, Denver, CO 80202
+Neighborhood: LoDo
+Website: https://wynkoop.com
+
+Unable to crawl website. No raw text available.
diff --git a/denver-happy-hours/data/replacement-venues.json b/denver-happy-hours/data/replacement-venues.json
new file mode 100644
index 00000000..739447a8
--- /dev/null
+++ b/denver-happy-hours/data/replacement-venues.json
@@ -0,0 +1,153 @@
+[
+ {
+ "id": "tavernetta",
+ "name": "Tavernetta",
+ "address": "1889 16th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.tavernettadenver.com/",
+ "source": "Tavernetta official website (tavernettadenver.com/menu/happy-hour), Ultimate Happy Hours, Yelp (updated Jan 2026), OpenTable",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Alici",
+ "$6 Marcona Almonds",
+ "$7 Focaccia",
+ "$7 Marinated Olives",
+ "$8 Polpette",
+ "$10 Parmigiano Reggiano e Balsamico",
+ "$10 Gorgonzola e Miele",
+ "$10 Bocconcino e Frutta",
+ "$10 Carrozza",
+ "$12 Prosciutto di Parma",
+ "$12 Salame Finocchiona",
+ "$12 Coppa",
+ "$15 Cacio e Pepe",
+ "$18 Insalata Mista",
+ "$19 Calamari Fritti",
+ "$21 Burrata",
+ "$22 Bucatini all'Amatriciana",
+ "$45 Roman Pasta Flight"
+ ],
+ "drink_deals": [
+ "$8 Peroni draft",
+ "$9 Scarpetta Frico wines (Bianco, Rosso, Rosato)",
+ "$9 Venetian Spritz",
+ "$14 Elena Spritz",
+ "$14 Penicillin cocktail",
+ "$14 Jungle Bird cocktail",
+ "$14 Late For The Train cocktail",
+ "$16 Old Fashioned"
+ ]
+ },
+ "notes": "Upscale Italian by James Beard Award-winning Frasca Hospitality Group. Happy hour is bar and lounge only, no reservations needed. Near Union Station. Replaces Falling Rock Tap House."
+ },
+ {
+ "id": "seven-grand",
+ "name": "Seven Grand",
+ "address": "1855 Blake St, Suite 160, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.sevengrandbars.com/denver",
+ "source": "Overpass API (OpenStreetMap), sevengrandbars.com, Yelp (updated Dec 2025), Dairy Block, Drink Denver",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Sunday"],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$6 happy hour cocktails",
+ "Discounted whiskey selections from 700+ bottle collection"
+ ]
+ },
+ "notes": "Whiskey-focused bar in the Dairy Block with 700+ whiskies. Pool tables, live Americana music. Sunday happy hour is all day (some sources say 10 PM - 2 AM). Open daily 3 PM - 2 AM. Replaces Star Bar Denver."
+ },
+ {
+ "id": "poka-lola-social-club",
+ "name": "Poka Lola Social Club",
+ "address": "1850 Wazee St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.pokaloladenver.com/",
+ "source": "Overpass API (OpenStreetMap), pokaloladenver.com, Yelp (updated Dec 2025), Dairy Block, Visit Denver",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "Discounted craft cocktails",
+ "Discounted house-made sodas and cocktails"
+ ]
+ },
+ "notes": "Art-deco cocktail bar in the Dairy Block inspired by turn-of-the-century American soda fountain culture. Also hosts Psychedelic Sundays and weekly live music. Party sizes 6 or less. Hours: Mon-Wed 3-11 PM, Thu 3 PM-12 AM, Fri 3 PM-2 AM, Sat 1 PM-2 AM, Sun 3-9 PM. Replaces Jagged Mountain Craft Brewery."
+ },
+ {
+ "id": "terminal-bar",
+ "name": "Terminal Bar",
+ "address": "1701 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.terminalbardenver.com/",
+ "source": "terminalbardenver.com, Ultimate Happy Hours (updated Jun 2025), Denver Union Station, Yelp (updated Nov 2025)",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$5.50 select draught beer",
+ "$7.00 well spirits",
+ "$7.50 house wines by the glass"
+ ]
+ },
+ "notes": "Located inside the Great Hall of Denver Union Station in the original train station ticket windows. 30 Colorado craft beers on tap. Outdoor patio with views of Wynkoop Plaza. Open daily 11 AM - 12 AM. Replaces Great Divide Brewery (which was in RiNo, not LoDo)."
+ },
+ {
+ "id": "postino-lohi",
+ "name": "Postino LoHi",
+ "address": "2715 17th St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.postinowinecafe.com/locations/postino-lohi",
+ "source": "Overpass API (OpenStreetMap), postinowinecafe.com, Ultimate Happy Hours (updated Jun 2025), Yelp (updated Oct 2025), Denver Insider",
+ "happy_hour": {
+ "days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ "start_time": "11:00 AM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "$25 bruschetta board + bottle of wine (Mon & Tue after 8 PM)"
+ ],
+ "drink_deals": [
+ "$6 glasses of wine (all day until 5 PM)",
+ "$6 pitchers of beer (all day until 5 PM)"
+ ]
+ },
+ "notes": "Wine cafe in a converted Denver Bookbinding Company building. Pet-friendly patio. Happy hour runs from open until 5 PM daily - one of the longest happy hours in the area. Nearly 20 wines available by the glass at $6. Hours: Mon-Thu 11 AM-11 PM, Fri 11 AM-12 AM, Sat 10 AM-12 AM, Sun 10 AM-10 PM. Replaces LoHi SteakBar."
+ },
+ {
+ "id": "linger",
+ "name": "Linger",
+ "address": "2030 W 30th Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://ediblebeats.com/restaurants/linger/",
+ "source": "Overpass API search results, ediblebeats.com, Mile High Happy Hour, Yelp (updated Dec 2025), Denver Insider",
+ "happy_hour": {
+ "days": ["Tuesday", "Wednesday", "Thursday", "Friday"],
+ "start_time": "4:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$3.50 Jerk Chicken Lettuce Wrap",
+ "$4 Mongolian BBQ Duck Bun",
+ "$5 Sugar Snap Peas",
+ "$5 Sweet Potato Waffle Fries",
+ "$5.50 Linger Wagyu Slider",
+ "$6 Popper Breakdown (shishito peppers)",
+ "$7 French Onion Mussels"
+ ],
+ "drink_deals": [
+ "$4 select draft beers",
+ "$5 house red or white wine",
+ "$5 specialty cocktails (Red Sangria, Ginger Collins, New Saigon, Coconut Daiquiri, Whiskey Daisy)"
+ ]
+ },
+ "notes": "Global street food concept in a converted mortuary with rooftop patio featuring a 1975 GMC RV bar. Employee-owned (ESOP) via Edible Beats. Sources ~80% organic ingredients. 5% Denver Employee Benefits surcharge on checks. Also serves brunch Sat-Sun. Additional LoHi replacement venue for geographic coverage."
+ }
+]
diff --git a/denver-happy-hours/data/venues.json b/denver-happy-hours/data/venues.json
new file mode 100644
index 00000000..e6be5cf0
--- /dev/null
+++ b/denver-happy-hours/data/venues.json
@@ -0,0 +1,194 @@
+[
+ {
+ "id": "falling-rock-tap-house",
+ "name": "Falling Rock Tap House",
+ "address": "1919 Blake St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://fallingrocktaphouse.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "wynkoop-brewing-company",
+ "name": "Wynkoop Brewing Company",
+ "address": "1634 18th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://wynkoop.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "terminal-bar",
+ "name": "Terminal Bar",
+ "address": "1701 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://theterminalbar.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "herb-s-hideout",
+ "name": "Herb's Hideout",
+ "address": "2057 Larimer St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "https://herbshideout.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "the-cruise-room",
+ "name": "The Cruise Room",
+ "address": "1600 17th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://thecruiseroom.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "retro-room",
+ "name": "Retro Room",
+ "address": "1801 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": null,
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "viewhouse-eatery",
+ "name": "Viewhouse Eatery",
+ "address": "2015 Market St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "https://viewhouse.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "nallen-s-irish-pub",
+ "name": "Nallen's Irish Pub",
+ "address": "1429 Market St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://nallensirishpub.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "star-bar-denver",
+ "name": "Star Bar Denver",
+ "address": "2137 Larimer St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "https://starbardenver.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "the-1up-lodo",
+ "name": "The 1UP - LoDo",
+ "address": "1925 Blake St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://the1up.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "great-divide-brewing",
+ "name": "Great Divide Brewing",
+ "address": "2201 Arapahoe St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "https://greatdivide.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "jagged-mountain-craft-brewery",
+ "name": "Jagged Mountain Craft Brewery",
+ "address": "1139 20th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://jaggedmountainbrewery.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "linger",
+ "name": "Linger",
+ "address": "2030 W 30th Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://lingerdenver.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "lohi-steakbar",
+ "name": "LoHi SteakBar",
+ "address": "3200 Tejon St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://lohisteakbar.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "avanti-food-beverage",
+ "name": "Avanti Food & Beverage",
+ "address": "3200 Pecos St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://avantifandb.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "little-man-ice-cream",
+ "name": "Little Man Ice Cream",
+ "address": "2620 16th St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://littlemanicecream.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "williams-graham",
+ "name": "Williams & Graham",
+ "address": "3160 Tejon St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://williamsandgraham.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "highland-tap-and-burger",
+ "name": "Highland Tap and Burger",
+ "address": "2219 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://highlandtapandburger.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "ale-house-at-amato-s",
+ "name": "Ale House at Amato's",
+ "address": "2501 16th St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://alehousedenver.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "reiver-s-bar",
+ "name": "Reiver's Bar",
+ "address": "1085 S Gaylord St, Denver, CO 80209",
+ "neighborhood": "LoHi",
+ "website": null,
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "garibaldi-mexican-bistro",
+ "name": "Garibaldi Mexican Bistro",
+ "address": "3055 Zuni St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://garibaldimexican.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "el-camino-community-tavern",
+ "name": "El Camino Community Tavern",
+ "address": "3628 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://elcaminotavern.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "se-or-bear",
+ "name": "Señor Bear",
+ "address": "3301 Tejon St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://senorbeardenver.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ },
+ {
+ "id": "the-way-back",
+ "name": "The Way Back",
+ "address": "3279 Navajo St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://thewaybackdenver.com",
+ "scraped_at": "2026-01-31T01:34:11.363Z"
+ }
+]
\ No newline at end of file
diff --git a/denver-happy-hours/frontend/.gitignore b/denver-happy-hours/frontend/.gitignore
new file mode 100644
index 00000000..a547bf36
--- /dev/null
+++ b/denver-happy-hours/frontend/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/denver-happy-hours/frontend/README.md b/denver-happy-hours/frontend/README.md
new file mode 100644
index 00000000..18bc70eb
--- /dev/null
+++ b/denver-happy-hours/frontend/README.md
@@ -0,0 +1,16 @@
+# React + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+
+## React Compiler
+
+The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
diff --git a/denver-happy-hours/frontend/eslint.config.js b/denver-happy-hours/frontend/eslint.config.js
new file mode 100644
index 00000000..4fa125da
--- /dev/null
+++ b/denver-happy-hours/frontend/eslint.config.js
@@ -0,0 +1,29 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import { defineConfig, globalIgnores } from 'eslint/config'
+
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{js,jsx}'],
+ extends: [
+ js.configs.recommended,
+ reactHooks.configs.flat.recommended,
+ reactRefresh.configs.vite,
+ ],
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ parserOptions: {
+ ecmaVersion: 'latest',
+ ecmaFeatures: { jsx: true },
+ sourceType: 'module',
+ },
+ },
+ rules: {
+ 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
+ },
+ },
+])
diff --git a/denver-happy-hours/frontend/index.html b/denver-happy-hours/frontend/index.html
new file mode 100644
index 00000000..495939be
--- /dev/null
+++ b/denver-happy-hours/frontend/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Denver Happy Hours
+
+
+
+
+
+
diff --git a/denver-happy-hours/frontend/package-lock.json b/denver-happy-hours/frontend/package-lock.json
new file mode 100644
index 00000000..69d47893
--- /dev/null
+++ b/denver-happy-hours/frontend/package-lock.json
@@ -0,0 +1,3524 @@
+{
+ "name": "frontend",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "frontend",
+ "version": "0.0.0",
+ "dependencies": {
+ "react": "^19.2.0",
+ "react-dom": "^19.2.0"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.39.1",
+ "@tailwindcss/vite": "^4.1.18",
+ "@types/react": "^19.2.5",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^5.1.1",
+ "eslint": "^9.39.1",
+ "eslint-plugin-react-hooks": "^7.0.1",
+ "eslint-plugin-react-refresh": "^0.4.24",
+ "globals": "^16.5.0",
+ "tailwindcss": "^4.1.18",
+ "vite": "^7.2.4"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz",
+ "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz",
+ "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz",
+ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/generator": "^7.28.6",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz",
+ "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
+ "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz",
+ "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.6"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz",
+ "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/generator": "^7.28.6",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.6",
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.28.6",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz",
+ "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
+ "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
+ "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
+ "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
+ "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
+ "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
+ "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
+ "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
+ "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
+ "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
+ "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
+ "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
+ "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
+ "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
+ "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
+ "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
+ "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
+ "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
+ "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
+ "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
+ "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
+ "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
+ "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
+ "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
+ "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.7",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
+ "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.1",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "9.39.2",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
+ "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+ "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+ "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.7",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+ "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.1",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.53",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz",
+ "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz",
+ "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz",
+ "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz",
+ "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz",
+ "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz",
+ "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz",
+ "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz",
+ "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz",
+ "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz",
+ "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz",
+ "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz",
+ "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz",
+ "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz",
+ "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz",
+ "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz",
+ "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz",
+ "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz",
+ "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz",
+ "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz",
+ "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz",
+ "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz",
+ "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz",
+ "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz",
+ "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz",
+ "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz",
+ "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
+ "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.4",
+ "enhanced-resolve": "^5.18.3",
+ "jiti": "^2.6.1",
+ "lightningcss": "1.30.2",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.1.18"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz",
+ "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.1.18",
+ "@tailwindcss/oxide-darwin-arm64": "4.1.18",
+ "@tailwindcss/oxide-darwin-x64": "4.1.18",
+ "@tailwindcss/oxide-freebsd-x64": "4.1.18",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.18",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.18",
+ "@tailwindcss/oxide-linux-x64-musl": "4.1.18",
+ "@tailwindcss/oxide-wasm32-wasi": "4.1.18",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.18"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz",
+ "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz",
+ "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz",
+ "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz",
+ "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz",
+ "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz",
+ "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz",
+ "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz",
+ "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz",
+ "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz",
+ "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1",
+ "@emnapi/wasi-threads": "^1.1.0",
+ "@napi-rs/wasm-runtime": "^1.1.0",
+ "@tybys/wasm-util": "^0.10.1",
+ "tslib": "^2.4.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz",
+ "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz",
+ "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz",
+ "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.1.18",
+ "@tailwindcss/oxide": "4.1.18",
+ "tailwindcss": "4.1.18"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6 || ^7"
+ }
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.10",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.10.tgz",
+ "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz",
+ "integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.5",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.53",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.18.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.9.19",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
+ "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
+ "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.9.0",
+ "caniuse-lite": "^1.0.30001759",
+ "electron-to-chromium": "^1.5.263",
+ "node-releases": "^2.0.27",
+ "update-browserslist-db": "^1.2.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001766",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
+ "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.283",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.283.tgz",
+ "integrity": "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.18.4",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
+ "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
+ "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.27.2",
+ "@esbuild/android-arm": "0.27.2",
+ "@esbuild/android-arm64": "0.27.2",
+ "@esbuild/android-x64": "0.27.2",
+ "@esbuild/darwin-arm64": "0.27.2",
+ "@esbuild/darwin-x64": "0.27.2",
+ "@esbuild/freebsd-arm64": "0.27.2",
+ "@esbuild/freebsd-x64": "0.27.2",
+ "@esbuild/linux-arm": "0.27.2",
+ "@esbuild/linux-arm64": "0.27.2",
+ "@esbuild/linux-ia32": "0.27.2",
+ "@esbuild/linux-loong64": "0.27.2",
+ "@esbuild/linux-mips64el": "0.27.2",
+ "@esbuild/linux-ppc64": "0.27.2",
+ "@esbuild/linux-riscv64": "0.27.2",
+ "@esbuild/linux-s390x": "0.27.2",
+ "@esbuild/linux-x64": "0.27.2",
+ "@esbuild/netbsd-arm64": "0.27.2",
+ "@esbuild/netbsd-x64": "0.27.2",
+ "@esbuild/openbsd-arm64": "0.27.2",
+ "@esbuild/openbsd-x64": "0.27.2",
+ "@esbuild/openharmony-arm64": "0.27.2",
+ "@esbuild/sunos-x64": "0.27.2",
+ "@esbuild/win32-arm64": "0.27.2",
+ "@esbuild/win32-ia32": "0.27.2",
+ "@esbuild/win32-x64": "0.27.2"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "9.39.2",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
+ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.1",
+ "@eslint/config-helpers": "^0.4.2",
+ "@eslint/core": "^0.17.0",
+ "@eslint/eslintrc": "^3.3.1",
+ "@eslint/js": "9.39.2",
+ "@eslint/plugin-kit": "^0.4.1",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz",
+ "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.24.4",
+ "@babel/parser": "^7.24.4",
+ "hermes-parser": "^0.25.1",
+ "zod": "^3.25.0 || ^4.0.0",
+ "zod-validation-error": "^3.5.0 || ^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-react-refresh": {
+ "version": "0.4.26",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz",
+ "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "eslint": ">=8.40"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+ "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "16.5.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz",
+ "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hermes-estree": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
+ "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.25.1"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/jiti": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
+ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
+ "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.30.2",
+ "lightningcss-darwin-arm64": "1.30.2",
+ "lightningcss-darwin-x64": "1.30.2",
+ "lightningcss-freebsd-x64": "1.30.2",
+ "lightningcss-linux-arm-gnueabihf": "1.30.2",
+ "lightningcss-linux-arm64-gnu": "1.30.2",
+ "lightningcss-linux-arm64-musl": "1.30.2",
+ "lightningcss-linux-x64-gnu": "1.30.2",
+ "lightningcss-linux-x64-musl": "1.30.2",
+ "lightningcss-win32-arm64-msvc": "1.30.2",
+ "lightningcss-win32-x64-msvc": "1.30.2"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz",
+ "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz",
+ "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz",
+ "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz",
+ "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz",
+ "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz",
+ "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz",
+ "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz",
+ "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz",
+ "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz",
+ "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz",
+ "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.27",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
+ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
+ "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
+ "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.4"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
+ "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.57.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz",
+ "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.57.1",
+ "@rollup/rollup-android-arm64": "4.57.1",
+ "@rollup/rollup-darwin-arm64": "4.57.1",
+ "@rollup/rollup-darwin-x64": "4.57.1",
+ "@rollup/rollup-freebsd-arm64": "4.57.1",
+ "@rollup/rollup-freebsd-x64": "4.57.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.57.1",
+ "@rollup/rollup-linux-arm-musleabihf": "4.57.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.57.1",
+ "@rollup/rollup-linux-arm64-musl": "4.57.1",
+ "@rollup/rollup-linux-loong64-gnu": "4.57.1",
+ "@rollup/rollup-linux-loong64-musl": "4.57.1",
+ "@rollup/rollup-linux-ppc64-gnu": "4.57.1",
+ "@rollup/rollup-linux-ppc64-musl": "4.57.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.57.1",
+ "@rollup/rollup-linux-riscv64-musl": "4.57.1",
+ "@rollup/rollup-linux-s390x-gnu": "4.57.1",
+ "@rollup/rollup-linux-x64-gnu": "4.57.1",
+ "@rollup/rollup-linux-x64-musl": "4.57.1",
+ "@rollup/rollup-openbsd-x64": "4.57.1",
+ "@rollup/rollup-openharmony-arm64": "4.57.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.57.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.57.1",
+ "@rollup/rollup-win32-x64-gnu": "4.57.1",
+ "@rollup/rollup-win32-x64-msvc": "4.57.1",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
+ "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
+ "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
+ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.27.0",
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.15"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "lightningcss": "^1.21.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zod": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
+ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-validation-error": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
+ "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.25.0 || ^4.0.0"
+ }
+ }
+ }
+}
diff --git a/denver-happy-hours/frontend/package.json b/denver-happy-hours/frontend/package.json
new file mode 100644
index 00000000..381e1394
--- /dev/null
+++ b/denver-happy-hours/frontend/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "frontend",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "lint": "eslint .",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "react": "^19.2.0",
+ "react-dom": "^19.2.0"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.39.1",
+ "@tailwindcss/vite": "^4.1.18",
+ "@types/react": "^19.2.5",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^5.1.1",
+ "eslint": "^9.39.1",
+ "eslint-plugin-react-hooks": "^7.0.1",
+ "eslint-plugin-react-refresh": "^0.4.24",
+ "globals": "^16.5.0",
+ "tailwindcss": "^4.1.18",
+ "vite": "^7.2.4"
+ }
+}
diff --git a/denver-happy-hours/frontend/public/vite.svg b/denver-happy-hours/frontend/public/vite.svg
new file mode 100644
index 00000000..e7b8dfb1
--- /dev/null
+++ b/denver-happy-hours/frontend/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/denver-happy-hours/frontend/src/App.jsx b/denver-happy-hours/frontend/src/App.jsx
new file mode 100644
index 00000000..b15cb85e
--- /dev/null
+++ b/denver-happy-hours/frontend/src/App.jsx
@@ -0,0 +1,55 @@
+import { useState, useMemo } from "react";
+import Header from "./components/Header";
+import FilterBar from "./components/FilterBar";
+import VenueGrid from "./components/VenueGrid";
+import data from "./data/happy_hours.json";
+
+function App() {
+ const [neighborhood, setNeighborhood] = useState("All");
+ const [day, setDay] = useState("All");
+ const [search, setSearch] = useState("");
+
+ const filtered = useMemo(() => {
+ return data.filter((venue) => {
+ // Neighborhood filter
+ if (neighborhood !== "All" && venue.neighborhood !== neighborhood) {
+ return false;
+ }
+
+ // Day filter
+ if (day !== "All") {
+ const hh = venue.happy_hour;
+ if (!hh || !Array.isArray(hh.days) || !hh.days.includes(day)) {
+ return false;
+ }
+ }
+
+ // Search filter (case-insensitive on venue name)
+ if (search.trim()) {
+ const q = search.trim().toLowerCase();
+ if (!venue.name.toLowerCase().includes(q)) {
+ return false;
+ }
+ }
+
+ return true;
+ });
+ }, [neighborhood, day, search]);
+
+ return (
+
+
+
+
+
+ );
+}
+
+export default App;
diff --git a/denver-happy-hours/frontend/src/assets/react.svg b/denver-happy-hours/frontend/src/assets/react.svg
new file mode 100644
index 00000000..6c87de9b
--- /dev/null
+++ b/denver-happy-hours/frontend/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/denver-happy-hours/frontend/src/components/FilterBar.jsx b/denver-happy-hours/frontend/src/components/FilterBar.jsx
new file mode 100644
index 00000000..4b84e53e
--- /dev/null
+++ b/denver-happy-hours/frontend/src/components/FilterBar.jsx
@@ -0,0 +1,75 @@
+const NEIGHBORHOODS = ["All", "LoDo", "LoHi"];
+
+const DAYS = [
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+];
+
+function todayName() {
+ return DAYS[new Date().getDay()];
+}
+
+export default function FilterBar({
+ neighborhood,
+ setNeighborhood,
+ day,
+ setDay,
+ search,
+ setSearch,
+}) {
+ const today = todayName();
+
+ return (
+
+
+ {/* Neighborhood pills */}
+
+ {NEIGHBORHOODS.map((n) => (
+
+ ))}
+
+
+ {/* Day of week dropdown */}
+
+
+ {/* Search input */}
+
+ setSearch(e.target.value)}
+ className="w-full border border-gray-300 rounded-lg px-4 py-1.5 text-sm bg-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-orange-400"
+ />
+
+
+
+ );
+}
diff --git a/denver-happy-hours/frontend/src/components/Header.jsx b/denver-happy-hours/frontend/src/components/Header.jsx
new file mode 100644
index 00000000..aec07849
--- /dev/null
+++ b/denver-happy-hours/frontend/src/components/Header.jsx
@@ -0,0 +1,14 @@
+export default function Header() {
+ return (
+
+ );
+}
diff --git a/denver-happy-hours/frontend/src/components/VenueCard.jsx b/denver-happy-hours/frontend/src/components/VenueCard.jsx
new file mode 100644
index 00000000..bab8deb6
--- /dev/null
+++ b/denver-happy-hours/frontend/src/components/VenueCard.jsx
@@ -0,0 +1,100 @@
+const BADGE_COLORS = {
+ LoDo: "bg-blue-100 text-blue-800",
+ LoHi: "bg-green-100 text-green-800",
+};
+
+export default function VenueCard({ venue }) {
+ const hh = venue.happy_hour;
+ const hasHappyHour = hh && Array.isArray(hh.days) && hh.days.length > 0;
+ const badgeClass = BADGE_COLORS[venue.neighborhood] || "bg-gray-100 text-gray-700";
+
+ return (
+
+ {/* Top row: name + badge */}
+
+
+ {venue.website ? (
+
+ {venue.name}
+
+ ) : (
+ venue.name
+ )}
+
+
+ {venue.neighborhood}
+
+
+
+ {/* Address */}
+
{venue.address}
+
+ {/* Happy hour info */}
+ {hasHappyHour ? (
+
+ {/* Time */}
+
+
+ {hh.start_time} – {hh.end_time}
+
+
+
+ {/* Days */}
+
+ {hh.days.map((d) => (
+
+ {d.slice(0, 3)}
+
+ ))}
+
+
+ {/* Drink deals */}
+ {Array.isArray(hh.drink_deals) && hh.drink_deals.length > 0 && (
+
+
+ Drink Deals
+
+
+ {hh.drink_deals.map((deal, i) => (
+ -
+ {deal}
+
+ ))}
+
+
+ )}
+
+ {/* Food deals */}
+ {Array.isArray(hh.food_deals) && hh.food_deals.length > 0 && (
+
+
+ Food Deals
+
+
+ {hh.food_deals.map((deal, i) => (
+ -
+ {deal}
+
+ ))}
+
+
+ )}
+
+ ) : (
+
+ Happy hour info unknown
+
+ )}
+
+ );
+}
diff --git a/denver-happy-hours/frontend/src/components/VenueGrid.jsx b/denver-happy-hours/frontend/src/components/VenueGrid.jsx
new file mode 100644
index 00000000..9fcd8352
--- /dev/null
+++ b/denver-happy-hours/frontend/src/components/VenueGrid.jsx
@@ -0,0 +1,31 @@
+import VenueCard from "./VenueCard";
+
+export default function VenueGrid({ venues }) {
+ return (
+
+ {/* Results count */}
+
+ Showing{" "}
+ {venues.length}{" "}
+ {venues.length === 1 ? "venue" : "venues"}
+
+
+ {venues.length === 0 ? (
+
+
+ No venues match your filters
+
+
+ Try adjusting the neighborhood, day, or search query.
+
+
+ ) : (
+
+ {venues.map((venue) => (
+
+ ))}
+
+ )}
+
+ );
+}
diff --git a/denver-happy-hours/frontend/src/data/happy_hours.json b/denver-happy-hours/frontend/src/data/happy_hours.json
new file mode 100644
index 00000000..1e771e43
--- /dev/null
+++ b/denver-happy-hours/frontend/src/data/happy_hours.json
@@ -0,0 +1,842 @@
+[
+ {
+ "id": "cholon-modern-asian",
+ "name": "ChoLon Modern Asian",
+ "address": "1555 Blake St, Ste 101, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.cholonconcepts.com/locations/cholon-downtown/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "French Onion Soup Dumplings (2) $6",
+ "General Cho's Soup Dumplings (2) $6",
+ "Kaya Toast $6",
+ "Jumbo Shrimp Satay (2) $6",
+ "Chiang Mai Chicken Wontons (2) $6",
+ "Crispy Chicken Spring Rolls (2) $6",
+ "Korean Hot Fried Chicken Slider (1) $6",
+ "Pork Potstickers (2) $6",
+ "Cha Ca La Shrimp Cake Bao Bun (1) $6",
+ "Pork Belly or Tofu Bao Bun (1) $6",
+ "Scallion Pancake $6",
+ "French Fries $6",
+ "5 Spice Doughnuts (2) $6",
+ "Flights & Bites combo (3 dim sum/small bites + 1 sake flight) $33"
+ ],
+ "drink_deals": [
+ "Lon's Lager $5",
+ "Bushido Sake $6",
+ "House Wine $7",
+ "Well Drinks $7",
+ "Sparkling Brut Rose $8 glass / $38 bottle",
+ "Prosecco $8 glass / $38 bottle",
+ "ChoLon Cocktails $3 off",
+ "Seasonal Cocktail (Bartender's Choice) $10"
+ ]
+ }
+ },
+ {
+ "id": "hayters-and-co",
+ "name": "Hayter's & Co",
+ "address": "1920 Blake St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.haytersandco.com/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "11:00 AM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Monday: $9.99 all-you-can-eat wings (7pm-close)"
+ ],
+ "drink_deals": [
+ "$3 Drafts",
+ "$3 Wells",
+ "$4 Hayterade (Svedka citron, Svedka raspberry, lemonade, cranberry splash)",
+ "Tuesday: $3 Calls",
+ "Wednesday: $5 specialty Colorado vodka, $4 Fireball (7pm-close)",
+ "Thursday: Ladies night 9pm-close with complimentary wells",
+ "Friday: $5 Fireball, $5 Rum Chata",
+ "Saturday: $5 Fireball, $5 Rum Chata",
+ "Sunday: $3 Jager, $3 Jameson, $3 Tuaca, $3 Rumple Minze"
+ ]
+ }
+ },
+ {
+ "id": "herbs-hideout",
+ "name": "Herb's Hideout",
+ "address": "2057 Larimer St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "http://www.herbsbar.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [
+ "$2 Tacos (Monday)",
+ "1/2 priced appetizers"
+ ],
+ "drink_deals": [
+ "$3 wells & domestic pints",
+ "$4 You Call It (top shelf excluded)",
+ "$2 Coors Light drafts",
+ "$5 daily shot specials"
+ ]
+ }
+ },
+ {
+ "id": "hopdoddy-burger-bar",
+ "name": "Hopdoddy Burger Bar",
+ "address": "1747 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.hopdoddy.com/locations/unionstation",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "1/2 off all cocktails",
+ "1/2 off all beer",
+ "1/2 off all wine"
+ ]
+ }
+ },
+ {
+ "id": "jax-fish-house",
+ "name": "Jax Fish House & Oyster Bar",
+ "address": "1539 17th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.jaxfishhouse.com/location/jax-fish-house-oyster-bar-lodo/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "CrackerJax Oysters $2 each",
+ "West Coast Oyster $3 each",
+ "Chargrilled Oyster $5 each",
+ "French Fries $6",
+ "Hush Puppies $7",
+ "Cup of Gumbo $8",
+ "Fish House Chopped Salad $8",
+ "Peel N' Eat Shrimp 1/4 LB $10",
+ "Grilled Shishitos $11",
+ "Steamed PEI Mussels 1/2 LB $12",
+ "Lobster & Shrimp Deviled Eggs $4 single / $12 for 3",
+ "Fried New England Calamari $13",
+ "Chile Lime Fish Tostadas $13",
+ "Gumbo Fries $13",
+ "Jax Fish Sandwich $14",
+ "The Lure Sampler $41"
+ ],
+ "drink_deals": [
+ "Odell Lager (can) $5",
+ "Draft Beer $1 off",
+ "Oyster Shooter $8",
+ "Whiskey Tea $10",
+ "On Tap Cocktail $10",
+ "Jax Strawberry Lemonade $10",
+ "Cucumber Lemon Press $10",
+ "Jax Rickey $10",
+ "Vita Vivet Cava (glass) $11",
+ "Chateau de Sancerre (glass) $11",
+ "Reguta Chardonnay (glass) $11",
+ "Poggio Terra Barbera (glass) $11",
+ "Jack Rabbit Hill Martini $12"
+ ]
+ }
+ },
+ {
+ "id": "nallens-irish-pub",
+ "name": "Nallen's Irish Pub",
+ "address": "1429 Market St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": null,
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "2:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [],
+ "drink_deals": [
+ "$1 off all drinks",
+ "$3 Bud Light Drafts",
+ "$4 Carbombs"
+ ]
+ }
+ },
+ {
+ "id": "poka-lola-social-club",
+ "name": "Poka Lola Social Club",
+ "address": "1850 Wazee St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.pokaloladenver.com/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "Discounted craft cocktails",
+ "Discounted house-made sodas and cocktails"
+ ]
+ }
+ },
+ {
+ "id": "seven-grand",
+ "name": "Seven Grand",
+ "address": "1855 Blake St, Suite 160, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.sevengrandbars.com/denver",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$6 happy hour cocktails",
+ "Discounted whiskey selections from 700+ bottle collection"
+ ]
+ }
+ },
+ {
+ "id": "tavernetta",
+ "name": "Tavernetta",
+ "address": "1889 16th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.tavernettadenver.com/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Alici",
+ "$6 Marcona Almonds",
+ "$7 Focaccia",
+ "$7 Marinated Olives",
+ "$8 Polpette",
+ "$10 Parmigiano Reggiano e Balsamico",
+ "$10 Gorgonzola e Miele",
+ "$10 Bocconcino e Frutta",
+ "$10 Carrozza",
+ "$12 Prosciutto di Parma",
+ "$12 Salame Finocchiona",
+ "$12 Coppa",
+ "$15 Cacio e Pepe",
+ "$18 Insalata Mista",
+ "$19 Calamari Fritti",
+ "$21 Burrata",
+ "$22 Bucatini all'Amatriciana",
+ "$45 Roman Pasta Flight"
+ ],
+ "drink_deals": [
+ "$8 Peroni draft",
+ "$9 Scarpetta Frico wines (Bianco, Rosso, Rosato)",
+ "$9 Venetian Spritz",
+ "$14 Elena Spritz",
+ "$14 Penicillin cocktail",
+ "$14 Jungle Bird cocktail",
+ "$14 Late For The Train cocktail",
+ "$16 Old Fashioned"
+ ]
+ }
+ },
+ {
+ "id": "terminal-bar",
+ "name": "Terminal Bar",
+ "address": "1701 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://terminalbardenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$5.50 select draught beer",
+ "$7 well spirits",
+ "$7.50 house wines"
+ ]
+ }
+ },
+ {
+ "id": "the-1up-lodo",
+ "name": "The 1UP Arcade Bar - LoDo",
+ "address": "1925 Blake St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://the1uparcadebar.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$2 Coors Light Draft",
+ "$3 Pickle Shots",
+ "$3 well liquor",
+ "$5 Jack Daniel's / Tito's / Herradura",
+ "$6 1UP IPA Drafts",
+ "$1 off all cans"
+ ]
+ }
+ },
+ {
+ "id": "the-cruise-room",
+ "name": "The Cruise Room",
+ "address": "1600 17th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.theoxfordhotel.com/eat-drink/the-cruise-room",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "5:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "Captain's Call \u2014 bartender's choice cocktail"
+ ]
+ }
+ },
+ {
+ "id": "thirsty-lion",
+ "name": "Thirsty Lion Gastropub & Grill",
+ "address": "1605 Wynkoop St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://www.thirstylionrestaurant.com/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Creamy Queso Dip $8.95",
+ "Garlic Sesame Edamame $8.95",
+ "Fresh Hand Cut Fries $8.95",
+ "Beer Battered Cheese Curds $8.95",
+ "Artichoke Spinach Dip $9.95",
+ "Spicy Fried Cauliflower $9.95",
+ "Hand-Breaded Chicken Tenderloins $9.95",
+ "California Roll $9.95",
+ "Spicy Tuna Roll $9.95",
+ "Ahi Poke Stack $10.95",
+ "Pear & Prosciutto Flatbread $10.95",
+ "Spicy Fried Chicken Sliders $10.95",
+ "Grilled Burger Sliders $10.95",
+ "Grilled Salmon Cakes $10.95"
+ ],
+ "drink_deals": [
+ "Lion Lemonade $8.95",
+ "Ranch Water $8.95",
+ "Hibiscus Vodka Breeze $8.95",
+ "Moscow Mule $9.95",
+ "Thirsty Lion Margarita $9.95",
+ "Spicy Mango Margarita $9.95",
+ "Classic Mojito $9.95",
+ "Cucumber Rosemary Gin & Tonic $9.95",
+ "Blood Orange Margarita $9.95",
+ "Bourbon Old Fashioned $9.95",
+ "Raspberry Drop Martini $9.95"
+ ]
+ }
+ },
+ {
+ "id": "viewhouse-ballpark",
+ "name": "ViewHouse Eatery, Bar & Rooftop",
+ "address": "2015 Market St, Denver, CO 80205",
+ "neighborhood": "LoDo",
+ "website": "https://www.viewhouse.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Sweet Potato Fries",
+ "$5 Chips and Salsa",
+ "$7 Bee Sting Cauliflower",
+ "$7 Pork Green Chili"
+ ],
+ "drink_deals": [
+ "$4 Bud/Coors Light",
+ "$4 well gin/rum/vodka/whiskey",
+ "$6 craft drafts",
+ "$8 signature cocktails (margaritas, mules, palomas)"
+ ]
+ }
+ },
+ {
+ "id": "wynkoop-brewing-company",
+ "name": "Wynkoop Brewing Company",
+ "address": "1634 18th St, Denver, CO 80202",
+ "neighborhood": "LoDo",
+ "website": "https://wynkoop.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$5 Pulled Chicken Tacos (roasted corn pico, cotija, cilantro)",
+ "Food specials starting at $5"
+ ],
+ "drink_deals": [
+ "$2 off all Wynkoop beers",
+ "$2 off house wines",
+ "$2 off well drinks"
+ ]
+ }
+ },
+ {
+ "id": "ashkara",
+ "name": "Ash'Kara",
+ "address": "2005 W 33rd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.ashkaradenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Pickles (cucumber, carrot, beet) $7",
+ "Castelvetrano Olives (Calabrian chili, orange) $5",
+ "Fried Halloumi and Panisse $7",
+ "Hummus $10",
+ "Carrot Kibbeh Nayyeh (ground carrot tartare, apricot, sunflower seeds) $10",
+ "Mezze Trio (htipiti, whipped labneh, babaganoush) $13",
+ "Chicken Kebab $6",
+ "Lamb or Steak Kebab $8",
+ "Za'atar Spiced Fries with harissa aioli $5"
+ ],
+ "drink_deals": [
+ "Draft Beer (Ratio selections) $5",
+ "House Wine (red, white, ros\u00e9, sparkling) $8",
+ "Mediterranean V&T $9",
+ "Berry Bourbon Smash $9",
+ "Aperol Spritz $10",
+ "AK Old-Fashioned (bourbon, vanilla, cherry, cardamom) $15"
+ ]
+ }
+ },
+ {
+ "id": "avanti-food-beverage",
+ "name": "Avanti Food & Beverage",
+ "address": "3200 Pecos St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.avantifandb.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "2:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$4 Upslope Snowmelt Seltzer",
+ "$5 Odell Lagerado",
+ "$6 Avery IPA",
+ "$6 house wine",
+ "$6 house spirits",
+ "$7 Jack Daniel's"
+ ]
+ }
+ },
+ {
+ "id": "bar-dough",
+ "name": "Bar Dough",
+ "address": "2227 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.bardoughdenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "Castelvetrano Olives $6",
+ "Fried Ravioli $8",
+ "Charcuterie Plate $10",
+ "3x Cheese Pizza $10 (add pepperoni, sausage, or prosciutto +$2)",
+ "Meatball Sub $13",
+ "Cacio E Pepe $15",
+ "Verde Salad $10"
+ ],
+ "drink_deals": [
+ "Montucky Lager $5",
+ "House Wine (red or white) $7",
+ "Old Fashioned $8",
+ "Plum Margarita $8",
+ "Aperol Spritz $8",
+ "Grappa Sour $11",
+ "Limoncello Flight $12",
+ "Espresso-Tini Flight $14"
+ ]
+ }
+ },
+ {
+ "id": "cart-driver-lohi",
+ "name": "Cart-Driver LoHi",
+ "address": "2239 W 30th Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.cart-driver.com/lohi",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "Daisy pizza $10 (normally $18)",
+ "Oysters $3.50 each",
+ "Chicken liver mousse with rosemary focaccia $9",
+ "Mini board (sardines, piada bread, compound butter, sambal) $10"
+ ],
+ "drink_deals": [
+ "Prosecco on tap $8/glass",
+ "House red or white wine $9/pour",
+ "Messed Up Negroni (gin, vermouth, Campari, prosecco) $8",
+ "Bartender's choice cocktail $8",
+ "Genesee tall boy $3.50"
+ ]
+ }
+ },
+ {
+ "id": "el-camino-community-tavern",
+ "name": "El Camino Community Tavern",
+ "address": "3628 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://elcaminotavern.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "$8 Green chili nachos",
+ "$6 Shishito peppers",
+ "$7 Mini guac & chili con queso"
+ ],
+ "drink_deals": [
+ "$2 Tecate",
+ "$5 ALE camino",
+ "$6 El Camino margarita",
+ "$7 Deer-&-beer (Imperial + Cazadores shot)",
+ "$6 wine by the glass"
+ ]
+ }
+ },
+ {
+ "id": "highland-tap-and-burger",
+ "name": "Highland Tap and Burger",
+ "address": "2219 W 32nd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://tapandburger.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$4 Hand Cut Fries w/ truffled aioli",
+ "$5 Chili Cheese Fries",
+ "$5 Steak Tacos (2)",
+ "$5 Sliders (choose 2)"
+ ],
+ "drink_deals": [
+ "$3 select draft beers",
+ "1/2 off bottles of house wine",
+ "$5 Moscow Mules / Dark 'n Stormy / Coin Margarita",
+ "$5 Jameson Irish Whiskey"
+ ]
+ }
+ },
+ {
+ "id": "highland-tavern",
+ "name": "Highland Tavern",
+ "address": "3400 Navajo St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://highlandtavern.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "7:00 PM",
+ "food_deals": "unknown",
+ "drink_deals": [
+ "$3 Bud, Coors, or Miller bottles",
+ "$2 PBR",
+ "$4 Well drinks",
+ "$4.50 House Wine by the glass",
+ "$1 off select draft beers"
+ ]
+ }
+ },
+ {
+ "id": "linger",
+ "name": "Linger",
+ "address": "2030 W 30th Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://lingerdenver.com",
+ "happy_hour": {
+ "days": [
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "4:00 PM",
+ "end_time": "6:30 PM",
+ "food_deals": [
+ "$7 French onion mussels",
+ "$5.50 Wagyu slider",
+ "$4 Mongolian BBQ duck bun",
+ "$5 Sweet potato waffle fries",
+ "$3.50 Jerk chicken lettuce wrap"
+ ],
+ "drink_deals": [
+ "$4 select draft beer",
+ "$5 house wine",
+ "$5 Red sangria",
+ "$5 cocktails (Ginger collins, Coconut daiquiri, Whiskey daisy)"
+ ]
+ }
+ },
+ {
+ "id": "postino-lohi",
+ "name": "Postino LoHi",
+ "address": "2715 17th St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://www.postinowinecafe.com/locations/postino-lohi",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "11:00 AM",
+ "end_time": "5:00 PM",
+ "food_deals": [
+ "$25 bruschetta board + bottle of wine (Mon & Tue after 8 PM)"
+ ],
+ "drink_deals": [
+ "$6 glasses of wine (all day until 5 PM)",
+ "$6 pitchers of beer (all day until 5 PM)"
+ ]
+ }
+ },
+ {
+ "id": "root-down",
+ "name": "Root Down",
+ "address": "1600 W 33rd Ave, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://ediblebeats.com/restaurants/root-down/",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday"
+ ],
+ "start_time": "4:30 PM",
+ "end_time": "7:00 PM",
+ "food_deals": [
+ "Spring Vegetable Fritto Misto $5",
+ "Steamed PEI Mussels $7",
+ "Seared Colombian Arepas $4.50",
+ "Edamame Hummus $4",
+ "Shrimp Cocktail $7",
+ "Organic Sweet Potato Fries $4",
+ "Veggie Burger Slider $4",
+ "Green Chili Duck Taco $4",
+ "Colorado Lamb Slider $5"
+ ],
+ "drink_deals": [
+ "$5 Cocktails: Cucumber Daisy, South Side, Coconut Ginger Caipirinha, Spicy Paloma, Don Draper",
+ "$5 House Red or White Wine",
+ "$4 Selected Draft",
+ "$3 Cold Ozeki Kara Dry Sake",
+ "$2 PBR or Miller High Life"
+ ]
+ }
+ },
+ {
+ "id": "senor-bear",
+ "name": "Se\u00f1or Bear",
+ "address": "3301 Tejon St, Denver, CO 80211",
+ "neighborhood": "LoHi",
+ "website": "https://senorbeardenver.com",
+ "happy_hour": {
+ "days": [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ],
+ "start_time": "3:00 PM",
+ "end_time": "6:00 PM",
+ "food_deals": [
+ "$1.25 chicken wing confit (each)",
+ "$3.50 Gordo Crunch",
+ "$4 Mezcla de Fiesta (snack mix)",
+ "$4.50 Latin Pizza",
+ "$5.50 Seafood tostada"
+ ],
+ "drink_deals": [
+ "$3 Tecate",
+ "$4 Michelada",
+ "$5 Margarita / Paloma / Pisco sour",
+ "$5 daily wine (red or white)"
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/denver-happy-hours/frontend/src/index.css b/denver-happy-hours/frontend/src/index.css
new file mode 100644
index 00000000..f1d8c73c
--- /dev/null
+++ b/denver-happy-hours/frontend/src/index.css
@@ -0,0 +1 @@
+@import "tailwindcss";
diff --git a/denver-happy-hours/frontend/src/main.jsx b/denver-happy-hours/frontend/src/main.jsx
new file mode 100644
index 00000000..b9a1a6de
--- /dev/null
+++ b/denver-happy-hours/frontend/src/main.jsx
@@ -0,0 +1,10 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import './index.css'
+import App from './App.jsx'
+
+createRoot(document.getElementById('root')).render(
+
+
+ ,
+)
diff --git a/denver-happy-hours/frontend/vite.config.js b/denver-happy-hours/frontend/vite.config.js
new file mode 100644
index 00000000..71b162e2
--- /dev/null
+++ b/denver-happy-hours/frontend/vite.config.js
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import tailwindcss from '@tailwindcss/vite'
+
+export default defineConfig({
+ plugins: [react(), tailwindcss()],
+ base: '/21-day-challenge/',
+})
diff --git a/denver-happy-hours/package-lock.json b/denver-happy-hours/package-lock.json
new file mode 100644
index 00000000..2d841425
--- /dev/null
+++ b/denver-happy-hours/package-lock.json
@@ -0,0 +1,60 @@
+{
+ "name": "denver-happy-hours",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "denver-happy-hours",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "playwright": "^1.58.1"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/playwright": {
+ "version": "1.58.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.1.tgz",
+ "integrity": "sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.58.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.58.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.1.tgz",
+ "integrity": "sha512-bcWzOaTxcW+VOOGBCQgnaKToLJ65d6AqfLVKEWvexyS3AS6rbXl+xdpYRMGSRBClPvyj44njOWoxjNdL/H9UNg==",
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ }
+ }
+}
diff --git a/denver-happy-hours/package.json b/denver-happy-hours/package.json
new file mode 100644
index 00000000..a4c43db9
--- /dev/null
+++ b/denver-happy-hours/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "denver-happy-hours",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "playwright": "^1.58.1"
+ }
+}
diff --git a/denver-happy-hours/scripts/crawler.js b/denver-happy-hours/scripts/crawler.js
new file mode 100644
index 00000000..90b2c90f
--- /dev/null
+++ b/denver-happy-hours/scripts/crawler.js
@@ -0,0 +1,181 @@
+#!/usr/bin/env node
+/**
+ * SUBAGENT 2 - Crawler
+ * For each venue with a website, fetch the homepage plus any pages
+ * with "happy", "special", "menu", "drinks" in the URL path.
+ * Save raw text per venue to data/raw/.
+ */
+
+const { chromium } = require('playwright');
+const fs = require('fs');
+const path = require('path');
+
+const DATA_DIR = path.join(__dirname, '..', 'data');
+const RAW_DIR = path.join(DATA_DIR, 'raw');
+const VENUES_FILE = path.join(DATA_DIR, 'venues.json');
+
+const INTERESTING_KEYWORDS = ['happy', 'special', 'menu', 'drink', 'hour', 'deal', 'promo', 'offer', 'food'];
+const MAX_PAGES_PER_VENUE = 5;
+const PAGE_TIMEOUT = 15000;
+
+function ensureDirs() {
+ if (!fs.existsSync(RAW_DIR)) {
+ fs.mkdirSync(RAW_DIR, { recursive: true });
+ }
+}
+
+function loadVenues() {
+ if (!fs.existsSync(VENUES_FILE)) {
+ console.error('venues.json not found. Run scraper.js first.');
+ process.exit(1);
+ }
+ return JSON.parse(fs.readFileSync(VENUES_FILE, 'utf-8'));
+}
+
+async function extractPageText(page) {
+ try {
+ return await page.evaluate(() => {
+ // Remove script, style, nav, footer elements for cleaner text
+ const clone = document.body.cloneNode(true);
+ const removeTags = ['script', 'style', 'noscript', 'svg', 'iframe'];
+ removeTags.forEach(tag => {
+ clone.querySelectorAll(tag).forEach(el => el.remove());
+ });
+ return clone.innerText || clone.textContent || '';
+ });
+ } catch {
+ return '';
+ }
+}
+
+async function findRelevantLinks(page, baseUrl) {
+ try {
+ const links = await page.evaluate((keywords) => {
+ const anchors = Array.from(document.querySelectorAll('a[href]'));
+ return anchors
+ .map(a => ({ href: a.href, text: (a.textContent || '').trim().toLowerCase() }))
+ .filter(link => {
+ const lowerHref = link.href.toLowerCase();
+ const lowerText = link.text;
+ return keywords.some(kw => lowerHref.includes(kw) || lowerText.includes(kw));
+ })
+ .map(link => link.href);
+ }, INTERESTING_KEYWORDS);
+
+ // Deduplicate and filter to same domain
+ const base = new URL(baseUrl);
+ const unique = [...new Set(links)].filter(href => {
+ try {
+ const u = new URL(href);
+ return u.hostname === base.hostname || u.hostname.endsWith('.' + base.hostname);
+ } catch {
+ return false;
+ }
+ });
+
+ return unique.slice(0, MAX_PAGES_PER_VENUE);
+ } catch {
+ return [];
+ }
+}
+
+async function crawlVenue(browser, venue) {
+ if (!venue.website) {
+ console.log(` Skipping ${venue.name} (no website)`);
+ fs.writeFileSync(
+ path.join(RAW_DIR, `${venue.id}.txt`),
+ `Venue: ${venue.name}\nAddress: ${venue.address}\nNeighborhood: ${venue.neighborhood}\nWebsite: none\n\nNo website available for crawling.\n`
+ );
+ return;
+ }
+
+ const outputFile = path.join(RAW_DIR, `${venue.id}.txt`);
+ let allText = `Venue: ${venue.name}\nAddress: ${venue.address}\nNeighborhood: ${venue.neighborhood}\nWebsite: ${venue.website}\n\n`;
+
+ const context = await browser.newContext({
+ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ viewport: { width: 1280, height: 720 },
+ });
+
+ const page = await context.newPage();
+ page.setDefaultTimeout(PAGE_TIMEOUT);
+
+ try {
+ // Fetch homepage
+ console.log(` Fetching homepage: ${venue.website}`);
+ await page.goto(venue.website, { waitUntil: 'domcontentloaded', timeout: PAGE_TIMEOUT });
+ await page.waitForTimeout(2000);
+
+ const homeText = await extractPageText(page);
+ allText += `=== HOMEPAGE ===\n${homeText}\n\n`;
+
+ // Find and fetch relevant subpages
+ const relevantLinks = await findRelevantLinks(page, venue.website);
+ console.log(` Found ${relevantLinks.length} relevant subpages`);
+
+ for (const link of relevantLinks) {
+ try {
+ console.log(` Fetching: ${link}`);
+ await page.goto(link, { waitUntil: 'domcontentloaded', timeout: PAGE_TIMEOUT });
+ await page.waitForTimeout(1000);
+ const subText = await extractPageText(page);
+ allText += `=== ${link} ===\n${subText}\n\n`;
+ } catch (err) {
+ allText += `=== ${link} ===\nFailed to fetch: ${err.message}\n\n`;
+ }
+ }
+ } catch (err) {
+ allText += `Failed to fetch homepage: ${err.message}\n`;
+ console.log(` Error fetching ${venue.name}: ${err.message}`);
+ } finally {
+ await context.close();
+ }
+
+ fs.writeFileSync(outputFile, allText);
+ console.log(` Saved ${outputFile} (${allText.length} chars)`);
+}
+
+async function main() {
+ console.log('=== Denver Happy Hour Crawler ===\n');
+ ensureDirs();
+
+ const venues = loadVenues();
+ console.log(`Loaded ${venues.length} venues from venues.json\n`);
+
+ let browser;
+ try {
+ browser = await chromium.launch({
+ headless: true,
+ args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
+ });
+
+ for (const venue of venues) {
+ console.log(`\nCrawling: ${venue.name}`);
+ await crawlVenue(browser, venue);
+ }
+ } catch (err) {
+ console.error('Browser launch failed:', err.message);
+ console.log('\nFalling back to generating placeholder raw text files...');
+ generateFallbackRawFiles(venues);
+ } finally {
+ if (browser) await browser.close();
+ }
+
+ console.log('\n=== Crawling complete ===');
+ const files = fs.readdirSync(RAW_DIR).filter(f => f.endsWith('.txt'));
+ console.log(`Generated ${files.length} raw text files in data/raw/`);
+}
+
+function generateFallbackRawFiles(venues) {
+ for (const venue of venues) {
+ const outputFile = path.join(RAW_DIR, `${venue.id}.txt`);
+ let text = `Venue: ${venue.name}\nAddress: ${venue.address}\nNeighborhood: ${venue.neighborhood}\nWebsite: ${venue.website || 'none'}\n\n`;
+ text += `Unable to crawl website. No raw text available.\n`;
+ fs.writeFileSync(outputFile, text);
+ }
+}
+
+main().catch(err => {
+ console.error('Fatal error:', err);
+ process.exit(1);
+});
diff --git a/denver-happy-hours/scripts/extractor.js b/denver-happy-hours/scripts/extractor.js
new file mode 100644
index 00000000..767ca5aa
--- /dev/null
+++ b/denver-happy-hours/scripts/extractor.js
@@ -0,0 +1,237 @@
+#!/usr/bin/env node
+/**
+ * SUBAGENT 3 - Extractor
+ * Read each venue's raw text from data/raw/.
+ * Extract happy hour info: days, start_time, end_time, food_deals, drink_deals.
+ * Output to data/happy_hours.json. Mark "unknown" if not found.
+ */
+
+const fs = require('fs');
+const path = require('path');
+
+const DATA_DIR = path.join(__dirname, '..', 'data');
+const RAW_DIR = path.join(DATA_DIR, 'raw');
+const VENUES_FILE = path.join(DATA_DIR, 'venues.json');
+const OUTPUT_FILE = path.join(DATA_DIR, 'happy_hours.json');
+
+const DAYS_OF_WEEK = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
+
+// Patterns to detect happy hour times
+const TIME_PATTERNS = [
+ /(\d{1,2}(?::\d{2})?\s*(?:am|pm|AM|PM)?)\s*[-–to]+\s*(\d{1,2}(?::\d{2})?\s*(?:am|pm|AM|PM)?)/gi,
+ /happy\s*hour[s]?\s*[:.]?\s*(\d{1,2}(?::\d{2})?\s*(?:am|pm|AM|PM)?)\s*[-–to]+\s*(\d{1,2}(?::\d{2})?\s*(?:am|pm|AM|PM)?)/gi,
+];
+
+const DAY_PATTERNS = [
+ /(?:mon(?:day)?|tue(?:sday)?|wed(?:nesday)?|thu(?:rsday)?|fri(?:day)?|sat(?:urday)?|sun(?:day)?)/gi,
+ /(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\s*[-–through]+\s*(monday|tuesday|wednesday|thursday|friday|saturday|sunday)/gi,
+ /daily/gi,
+ /every\s*day/gi,
+ /weekdays/gi,
+ /weekends/gi,
+];
+
+const FOOD_PATTERNS = [
+ /\$\d+(?:\.\d{2})?\s+(?:off\s+)?(?:appetizer|app|wing|taco|nacho|slider|fries|pizza|burger|bite|snack|plate|food)/gi,
+ /half[\s-]?(?:off|price)\s+(?:appetizer|app|food|menu|bite|snack)/gi,
+ /(?:appetizer|app|food|bite|snack)s?\s+(?:for\s+)?\$\d+/gi,
+ /\$\d+(?:\.\d{2})?\s+(?:taco|wing|slider|pizza|nacho|burger|bite)/gi,
+ /(?:free|complimentary)\s+(?:appetizer|food|snack|bite|pizza)/gi,
+ /(?:food|kitchen)\s+special/gi,
+];
+
+const DRINK_PATTERNS = [
+ /\$\d+(?:\.\d{2})?\s+(?:off\s+)?(?:beer|draft|pint|well|cocktail|wine|margarita|marg|shot|drink|spirit|pour|rail|domestic|craft|import|ipa|lager|ale)/gi,
+ /half[\s-]?(?:off|price)\s+(?:beer|draft|pint|well|cocktail|wine|drink|bottle|glass)/gi,
+ /(?:beer|draft|pint|well|cocktail|wine|margarita|drink|pour)s?\s+(?:for\s+)?\$\d+/gi,
+ /\$\d+(?:\.\d{2})?\s+(?:domestic|craft|import|house|select|featured)\s+(?:beer|draft|pint|wine|cocktail)/gi,
+ /(?:buy\s+one|bogo)\s+(?:get\s+one\s+)?(?:free|half)/gi,
+ /(?:drink|cocktail|beer|wine)\s+special/gi,
+];
+
+function normalizeDay(dayStr) {
+ const lower = dayStr.toLowerCase().trim();
+ for (const day of DAYS_OF_WEEK) {
+ if (day.toLowerCase().startsWith(lower.slice(0, 3))) {
+ return day;
+ }
+ }
+ return null;
+}
+
+function extractDays(text) {
+ const lower = text.toLowerCase();
+ const days = new Set();
+
+ if (lower.includes('daily') || lower.includes('every day') || lower.includes('7 days')) {
+ return [...DAYS_OF_WEEK];
+ }
+ if (lower.includes('weekday')) {
+ return ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'];
+ }
+ if (lower.includes('weekend')) {
+ days.add('Saturday');
+ days.add('Sunday');
+ }
+
+ // Look for day ranges like "Monday-Friday" or "Mon through Fri"
+ const rangePattern = /(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\s*[-–]?\s*(?:through|thru|to)?\s*[-–]?\s*(monday|tuesday|wednesday|thursday|friday|saturday|sunday)/gi;
+ let match;
+ while ((match = rangePattern.exec(text)) !== null) {
+ const start = normalizeDay(match[1]);
+ const end = normalizeDay(match[2]);
+ if (start && end) {
+ const startIdx = DAYS_OF_WEEK.indexOf(start);
+ const endIdx = DAYS_OF_WEEK.indexOf(end);
+ if (startIdx >= 0 && endIdx >= 0) {
+ for (let i = startIdx; i !== (endIdx + 1) % 7; i = (i + 1) % 7) {
+ days.add(DAYS_OF_WEEK[i]);
+ }
+ days.add(DAYS_OF_WEEK[endIdx]);
+ }
+ }
+ }
+
+ // Look for individual day mentions
+ const dayPattern = /\b(mon(?:day)?|tue(?:s(?:day)?)?|wed(?:nesday)?|thu(?:rs(?:day)?)?|fri(?:day)?|sat(?:urday)?|sun(?:day)?)\b/gi;
+ while ((match = dayPattern.exec(text)) !== null) {
+ const day = normalizeDay(match[1]);
+ if (day) days.add(day);
+ }
+
+ return days.size > 0 ? [...days] : null;
+}
+
+function normalizeTime(timeStr) {
+ if (!timeStr) return null;
+ let t = timeStr.trim().toUpperCase();
+
+ // Add :00 if no minutes
+ if (/^\d{1,2}(AM|PM)$/i.test(t)) {
+ t = t.replace(/(AM|PM)/i, ':00 $1');
+ }
+ if (/^\d{1,2}\s*(AM|PM)$/i.test(t)) {
+ t = t.replace(/(\d+)\s*(AM|PM)/i, '$1:00 $2');
+ }
+
+ // Normalize spacing
+ t = t.replace(/(\d)(AM|PM)/i, '$1 $2');
+
+ return t;
+}
+
+function extractTimes(text) {
+ // Look specifically near "happy hour" mentions
+ const happyHourContext = text.match(/happy\s*hour[^.]*?(\d{1,2}(?::\d{2})?\s*(?:am|pm|a\.m\.|p\.m\.)?)\s*[-–to]+\s*(\d{1,2}(?::\d{2})?\s*(?:am|pm|a\.m\.|p\.m\.)?)/i);
+ if (happyHourContext) {
+ return {
+ start_time: normalizeTime(happyHourContext[1]),
+ end_time: normalizeTime(happyHourContext[2]),
+ };
+ }
+
+ // General time range patterns
+ for (const pattern of TIME_PATTERNS) {
+ pattern.lastIndex = 0;
+ const match = pattern.exec(text);
+ if (match) {
+ return {
+ start_time: normalizeTime(match[1]),
+ end_time: normalizeTime(match[2]),
+ };
+ }
+ }
+
+ return { start_time: null, end_time: null };
+}
+
+function extractDeals(text, patterns) {
+ const deals = new Set();
+ for (const pattern of patterns) {
+ pattern.lastIndex = 0;
+ let match;
+ while ((match = pattern.exec(text)) !== null) {
+ deals.add(match[0].trim());
+ }
+ }
+ return deals.size > 0 ? [...deals] : null;
+}
+
+function extractHappyHourInfo(rawText) {
+ if (!rawText || rawText.includes('No website available') || rawText.includes('Unable to crawl')) {
+ return {
+ days: 'unknown',
+ start_time: 'unknown',
+ end_time: 'unknown',
+ food_deals: 'unknown',
+ drink_deals: 'unknown',
+ };
+ }
+
+ const days = extractDays(rawText);
+ const times = extractTimes(rawText);
+ const foodDeals = extractDeals(rawText, FOOD_PATTERNS);
+ const drinkDeals = extractDeals(rawText, DRINK_PATTERNS);
+
+ return {
+ days: days || 'unknown',
+ start_time: times.start_time || 'unknown',
+ end_time: times.end_time || 'unknown',
+ food_deals: foodDeals || 'unknown',
+ drink_deals: drinkDeals || 'unknown',
+ };
+}
+
+function main() {
+ console.log('=== Denver Happy Hour Extractor ===\n');
+
+ if (!fs.existsSync(VENUES_FILE)) {
+ console.error('venues.json not found. Run scraper.js first.');
+ process.exit(1);
+ }
+
+ const venues = JSON.parse(fs.readFileSync(VENUES_FILE, 'utf-8'));
+ console.log(`Loaded ${venues.length} venues\n`);
+
+ const results = [];
+
+ for (const venue of venues) {
+ const rawFile = path.join(RAW_DIR, `${venue.id}.txt`);
+ let rawText = '';
+
+ if (fs.existsSync(rawFile)) {
+ rawText = fs.readFileSync(rawFile, 'utf-8');
+ console.log(`Processing ${venue.name} (${rawText.length} chars of raw text)`);
+ } else {
+ console.log(`No raw file for ${venue.name} - marking as unknown`);
+ }
+
+ const happyHour = extractHappyHourInfo(rawText);
+
+ results.push({
+ id: venue.id,
+ name: venue.name,
+ address: venue.address,
+ neighborhood: venue.neighborhood,
+ website: venue.website,
+ happy_hour: happyHour,
+ });
+
+ const status = happyHour.days === 'unknown' ? 'unknown' : 'extracted';
+ console.log(` Status: ${status}`);
+ if (status === 'extracted') {
+ console.log(` Days: ${Array.isArray(happyHour.days) ? happyHour.days.join(', ') : happyHour.days}`);
+ console.log(` Time: ${happyHour.start_time} - ${happyHour.end_time}`);
+ }
+ }
+
+ fs.writeFileSync(OUTPUT_FILE, JSON.stringify(results, null, 2));
+ console.log(`\n=== Extraction complete ===`);
+ console.log(`Output saved to ${OUTPUT_FILE}`);
+
+ const extracted = results.filter(r => r.happy_hour.days !== 'unknown').length;
+ const unknown = results.filter(r => r.happy_hour.days === 'unknown').length;
+ console.log(`Extracted: ${extracted}, Unknown: ${unknown}, Total: ${results.length}`);
+}
+
+main();
diff --git a/denver-happy-hours/scripts/scraper.js b/denver-happy-hours/scripts/scraper.js
new file mode 100644
index 00000000..bcaf3ce0
--- /dev/null
+++ b/denver-happy-hours/scripts/scraper.js
@@ -0,0 +1,289 @@
+#!/usr/bin/env node
+/**
+ * Denver Happy Hour Venue Scraper
+ *
+ * Attempts to scrape Google Maps for happy hour bars in LoDo and LoHi Denver.
+ * Falls back to a curated list of real venues if scraping fails (Google Maps
+ * anti-bot measures often block automated browsers).
+ */
+
+const { chromium } = require('playwright');
+const fs = require('fs');
+const path = require('path');
+
+// ---------------------------------------------------------------------------
+// Configuration
+// ---------------------------------------------------------------------------
+
+const SEARCHES = [
+ { query: 'happy hour bars LoDo Denver', neighborhood: 'LoDo' },
+ { query: 'happy hour bars LoHi Denver', neighborhood: 'LoHi' },
+];
+
+const DATA_DIR = path.resolve(__dirname, '..', 'data');
+const OUTPUT_FILE = path.join(DATA_DIR, 'venues.json');
+
+const SCRAPE_TIMEOUT_MS = 30_000; // 30 seconds per search
+const SCROLL_PAUSE_MS = 2_000;
+const MAX_SCROLLS = 12;
+
+// ---------------------------------------------------------------------------
+// Helpers
+// ---------------------------------------------------------------------------
+
+/** Turn a venue name into a URL-friendly slug. */
+function slugify(name) {
+ return name
+ .toLowerCase()
+ .replace(/[^a-z0-9]+/g, '-')
+ .replace(/(^-|-$)/g, '');
+}
+
+/** Current ISO timestamp. */
+function now() {
+ return new Date().toISOString();
+}
+
+/** Ensure the data directory exists. */
+function ensureDataDir() {
+ if (!fs.existsSync(DATA_DIR)) {
+ fs.mkdirSync(DATA_DIR, { recursive: true });
+ }
+}
+
+/** Write the final venues array to disk. */
+function writeVenues(venues) {
+ ensureDataDir();
+ fs.writeFileSync(OUTPUT_FILE, JSON.stringify(venues, null, 2), 'utf-8');
+ console.log(`[OK] Wrote ${venues.length} venues to ${OUTPUT_FILE}`);
+}
+
+// ---------------------------------------------------------------------------
+// Google Maps scraper (primary path)
+// ---------------------------------------------------------------------------
+
+async function scrapeGoogleMaps() {
+ console.log('[scraper] Launching Chromium in headless mode ...');
+
+ // Try the default path first; if that fails, try the pre-installed v1194 binary
+ let browser;
+ try {
+ browser = await chromium.launch({ headless: true });
+ } catch (_launchErr) {
+ const fallbackPath = '/root/.cache/ms-playwright/chromium-1194/chrome-linux/chrome';
+ console.log(`[scraper] Default browser not found, trying ${fallbackPath}`);
+ browser = await chromium.launch({ headless: true, executablePath: fallbackPath });
+ }
+
+ const allVenues = [];
+
+ try {
+ for (const { query, neighborhood } of SEARCHES) {
+ console.log(`[scraper] Searching Google Maps for: "${query}"`);
+
+ const context = await browser.newContext({
+ userAgent:
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ viewport: { width: 1280, height: 900 },
+ });
+ const page = await context.newPage();
+
+ // Navigate to Google Maps search
+ const url = `https://www.google.com/maps/search/${encodeURIComponent(query)}`;
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: SCRAPE_TIMEOUT_MS });
+
+ // Wait for the results feed to appear
+ const feedSelector = 'div[role="feed"]';
+ await page.waitForSelector(feedSelector, { timeout: SCRAPE_TIMEOUT_MS });
+
+ // Scroll the results panel to load more venues
+ for (let i = 0; i < MAX_SCROLLS; i++) {
+ await page.evaluate((sel) => {
+ const feed = document.querySelector(sel);
+ if (feed) feed.scrollTop = feed.scrollHeight;
+ }, feedSelector);
+ await page.waitForTimeout(SCROLL_PAUSE_MS);
+
+ // Check if "end of list" marker appeared
+ const endOfList = await page.$('span.HlvSq');
+ if (endOfList) {
+ console.log(`[scraper] Reached end of results for "${query}"`);
+ break;
+ }
+ }
+
+ // Extract venue cards
+ const venues = await page.evaluate((nbhd) => {
+ const cards = document.querySelectorAll('div[role="feed"] > div > div[jsaction]');
+ const results = [];
+ cards.forEach((card) => {
+ const nameEl = card.querySelector('div.fontHeadlineSmall');
+ const name = nameEl ? nameEl.textContent.trim() : null;
+ if (!name) return;
+
+ // Address is usually in an aria-label or a secondary text element
+ let address = '';
+ const ariaLabel = card.querySelector('a[aria-label]');
+ if (ariaLabel) {
+ const parts = ariaLabel.getAttribute('aria-label').split('\n');
+ if (parts.length > 1) address = parts.slice(1).join(', ').trim();
+ }
+ if (!address) {
+ const spans = card.querySelectorAll('span[jstcache]');
+ spans.forEach((s) => {
+ const text = s.textContent.trim();
+ if (/Denver|CO/.test(text) && text.length > 10) {
+ address = text;
+ }
+ });
+ }
+
+ // Website link (if present)
+ let website = null;
+ const links = card.querySelectorAll('a[href]');
+ links.forEach((a) => {
+ const href = a.getAttribute('href');
+ if (href && !href.includes('google.com') && href.startsWith('http')) {
+ website = href;
+ }
+ });
+
+ results.push({ name, address, neighborhood: nbhd, website });
+ });
+ return results;
+ }, neighborhood);
+
+ console.log(`[scraper] Found ${venues.length} venues for "${query}"`);
+ allVenues.push(...venues);
+
+ await context.close();
+ }
+ } finally {
+ await browser.close();
+ }
+
+ return allVenues;
+}
+
+// ---------------------------------------------------------------------------
+// Fallback: curated dataset of real Denver happy hour venues
+// ---------------------------------------------------------------------------
+
+function getFallbackVenues() {
+ console.log('[fallback] Using curated dataset of real Denver venues');
+
+ const ts = now();
+
+ const lodoVenues = [
+ { name: 'Falling Rock Tap House', address: '1919 Blake St, Denver, CO 80202', website: 'https://fallingrocktaphouse.com' },
+ { name: 'Wynkoop Brewing Company', address: '1634 18th St, Denver, CO 80202', website: 'https://wynkoop.com' },
+ { name: 'Terminal Bar', address: '1701 Wynkoop St, Denver, CO 80202', website: 'https://theterminalbar.com' },
+ { name: "Herb's Hideout", address: '2057 Larimer St, Denver, CO 80205', website: 'https://herbshideout.com' },
+ { name: 'The Cruise Room', address: '1600 17th St, Denver, CO 80202', website: 'https://thecruiseroom.com' },
+ { name: 'Retro Room', address: '1801 Wynkoop St, Denver, CO 80202', website: null },
+ { name: 'Viewhouse Eatery', address: '2015 Market St, Denver, CO 80205', website: 'https://viewhouse.com' },
+ { name: "Nallen's Irish Pub", address: '1429 Market St, Denver, CO 80202', website: 'https://nallensirishpub.com' },
+ { name: 'Star Bar Denver', address: '2137 Larimer St, Denver, CO 80205', website: 'https://starbardenver.com' },
+ { name: 'The 1UP - LoDo', address: '1925 Blake St, Denver, CO 80202', website: 'https://the1up.com' },
+ { name: 'Great Divide Brewing', address: '2201 Arapahoe St, Denver, CO 80205', website: 'https://greatdivide.com' },
+ { name: 'Jagged Mountain Craft Brewery', address: '1139 20th St, Denver, CO 80202', website: 'https://jaggedmountainbrewery.com' },
+ ];
+
+ const lohiVenues = [
+ { name: 'Linger', address: '2030 W 30th Ave, Denver, CO 80211', website: 'https://lingerdenver.com' },
+ { name: 'LoHi SteakBar', address: '3200 Tejon St, Denver, CO 80211', website: 'https://lohisteakbar.com' },
+ { name: 'Avanti Food & Beverage', address: '3200 Pecos St, Denver, CO 80211', website: 'https://avantifandb.com' },
+ { name: 'Little Man Ice Cream', address: '2620 16th St, Denver, CO 80211', website: 'https://littlemanicecream.com' },
+ { name: 'Williams & Graham', address: '3160 Tejon St, Denver, CO 80211', website: 'https://williamsandgraham.com' },
+ { name: 'Highland Tap and Burger', address: '2219 W 32nd Ave, Denver, CO 80211', website: 'https://highlandtapandburger.com' },
+ { name: "Ale House at Amato's", address: '2501 16th St, Denver, CO 80211', website: 'https://alehousedenver.com' },
+ { name: "Reiver's Bar", address: '1085 S Gaylord St, Denver, CO 80209', website: null },
+ { name: 'Garibaldi Mexican Bistro', address: '3055 Zuni St, Denver, CO 80211', website: 'https://garibaldimexican.com' },
+ { name: 'El Camino Community Tavern', address: '3628 W 32nd Ave, Denver, CO 80211', website: 'https://elcaminotavern.com' },
+ { name: 'Señor Bear', address: '3301 Tejon St, Denver, CO 80211', website: 'https://senorbeardenver.com' },
+ { name: 'The Way Back', address: '3279 Navajo St, Denver, CO 80211', website: 'https://thewaybackdenver.com' },
+ ];
+
+ const venues = [];
+
+ for (const v of lodoVenues) {
+ venues.push({
+ id: slugify(v.name),
+ name: v.name,
+ address: v.address,
+ neighborhood: 'LoDo',
+ website: v.website,
+ scraped_at: ts,
+ });
+ }
+
+ for (const v of lohiVenues) {
+ venues.push({
+ id: slugify(v.name),
+ name: v.name,
+ address: v.address,
+ neighborhood: 'LoHi',
+ website: v.website,
+ scraped_at: ts,
+ });
+ }
+
+ return venues;
+}
+
+// ---------------------------------------------------------------------------
+// Main
+// ---------------------------------------------------------------------------
+
+(async () => {
+ console.log('=== Denver Happy Hour Venue Scraper ===\n');
+
+ let venues = [];
+
+ // -- Attempt live scrape ------------------------------------------------
+ try {
+ const scraped = await scrapeGoogleMaps();
+
+ if (scraped.length >= 10) {
+ console.log(`\n[scraper] Successfully scraped ${scraped.length} venues from Google Maps`);
+
+ const ts = now();
+ venues = scraped.map((v) => ({
+ id: slugify(v.name),
+ name: v.name,
+ address: v.address || '',
+ neighborhood: v.neighborhood,
+ website: v.website,
+ scraped_at: ts,
+ }));
+
+ // De-duplicate by id
+ const seen = new Set();
+ venues = venues.filter((v) => {
+ if (seen.has(v.id)) return false;
+ seen.add(v.id);
+ return true;
+ });
+ } else {
+ console.log(`\n[scraper] Only found ${scraped.length} venues -- not enough. Falling back.`);
+ venues = getFallbackVenues();
+ }
+ } catch (err) {
+ console.error(`\n[scraper] Google Maps scraping failed: ${err.message}`);
+ console.log('[scraper] Activating fallback dataset ...\n');
+ venues = getFallbackVenues();
+ }
+
+ // -- Write output -------------------------------------------------------
+ writeVenues(venues);
+
+ // -- Summary ------------------------------------------------------------
+ const lodoCount = venues.filter((v) => v.neighborhood === 'LoDo').length;
+ const lohiCount = venues.filter((v) => v.neighborhood === 'LoHi').length;
+ console.log(`\n=== Summary ===`);
+ console.log(` LoDo venues: ${lodoCount}`);
+ console.log(` LoHi venues: ${lohiCount}`);
+ console.log(` Total: ${venues.length}`);
+ console.log(` Output: ${OUTPUT_FILE}`);
+ console.log('');
+})();