Compare commits
8
Commits
9883323161
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e075874186 | ||
|
|
25e39beef8 | ||
|
|
d561326b84 | ||
|
|
d607badac1 | ||
|
|
5d2e9cb7e5 | ||
|
|
0732dd662d | ||
|
|
2b1c226d46 | ||
|
|
4d7abdbb3b |
@@ -0,0 +1,5 @@
|
|||||||
|
[ 53923ms] [INFO] Autofocus processing was blocked because a document's URL has a fragment '#gf_5'. @ https://hubinsurance.mystagingwebsite.com/:0
|
||||||
|
[ 111627ms] [LOG] JQMIGRATE: Migrate is installed, version 3.4.0 @ https://consumeruat.instanda.us/Scripts/jquery-migrate-3.4.0.min.js:1
|
||||||
|
[ 112217ms] [LOG] initial resources loaded. @ https://consumeruat.instanda.us/Public/PublicUatUserLogin:208
|
||||||
|
[ 112218ms] [WARNING] Site Environment is not present in Instanda variables. Using URL as backup. @ https://blue-sand-09e2e8710.3.azurestaticapps.net/src/instanda.scripts.js:37
|
||||||
|
[ 112355ms] [LOG] HCC Engine found. Initializing... @ https://blue-sand-09e2e8710.3.azurestaticapps.net/src/UAT/SPG/instanda.spg.general.js:41
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
- generic [active] [ref=e1]:
|
||||||
|
- link "Skip to content" [ref=e2] [cursor=pointer]:
|
||||||
|
- /url: "#content"
|
||||||
|
- banner "Site" [ref=e3]:
|
||||||
|
- generic [ref=e4]:
|
||||||
|
- link "HUB Insurance" [ref=e6] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- img "HUB Insurance" [ref=e7]
|
||||||
|
- navigation "Primary" [ref=e8]:
|
||||||
|
- list [ref=e11]:
|
||||||
|
- listitem [ref=e12]:
|
||||||
|
- link "About" [ref=e13] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/about
|
||||||
|
- listitem [ref=e14]:
|
||||||
|
- link "Contact" [ref=e15] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- listitem [ref=e16]:
|
||||||
|
- link "Get a Quote" [ref=e17] [cursor=pointer]:
|
||||||
|
- /url: "#get-a-quote"
|
||||||
|
- generic [ref=e19]:
|
||||||
|
- heading "Special Event Insurance" [level=1] [ref=e20]:
|
||||||
|
- text: Special
|
||||||
|
- emphasis [ref=e21]: Event
|
||||||
|
- text: Insurance
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=e22]: "{Hero Content} Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||||
|
- list [ref=e23]:
|
||||||
|
- listitem [ref=e24]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e25]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e26]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e27]: Lorem ipsum dolor
|
||||||
|
- paragraph
|
||||||
|
- link "Hero CTA Lorem" [ref=e28] [cursor=pointer]:
|
||||||
|
- /url: https://www.getfused.com
|
||||||
|
- main [ref=e32]:
|
||||||
|
- generic [ref=e33]:
|
||||||
|
- generic [ref=e34]:
|
||||||
|
- generic [ref=e35]:
|
||||||
|
- paragraph [ref=e36]: How it Works
|
||||||
|
- heading "Three Simple Steps" [level=2] [ref=e37]
|
||||||
|
- generic [ref=e38]:
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=e39]:
|
||||||
|
- generic [ref=e40]:
|
||||||
|
- heading "Start a Quote" [level=2] [ref=e41]
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=e42]: An asterisk (*) indicates a required field.
|
||||||
|
- generic [ref=e43]:
|
||||||
|
- generic [ref=e45]:
|
||||||
|
- generic [ref=e46]:
|
||||||
|
- generic [ref=e47]:
|
||||||
|
- text: Event Role
|
||||||
|
- generic [ref=e49]: "*"
|
||||||
|
- combobox "Event Role *" [ref=e51]:
|
||||||
|
- option [selected]
|
||||||
|
- option "Event Host or Organizer"
|
||||||
|
- option "Vendor, Exhibitor or Subcontractor"
|
||||||
|
- option "Performer, Entertainer or DJ"
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- generic [ref=e53]:
|
||||||
|
- text: Activity / Event Type
|
||||||
|
- generic [ref=e55]: "*"
|
||||||
|
- combobox "Activity / Event Type *" [ref=e57]:
|
||||||
|
- option [selected]
|
||||||
|
- option "Animal Adoption Event"
|
||||||
|
- option "Animal Shows"
|
||||||
|
- option "Antique Show"
|
||||||
|
- option "Art Festival"
|
||||||
|
- option "Art Show"
|
||||||
|
- option "Auction"
|
||||||
|
- option "Award Presentation"
|
||||||
|
- option "Baby Shower"
|
||||||
|
- option "Bachelor Party"
|
||||||
|
- option "Bachelorette Party"
|
||||||
|
- option "Badminton Tournament / Event"
|
||||||
|
- option "Bake Sale"
|
||||||
|
- option "Ballet"
|
||||||
|
- option "Banquet"
|
||||||
|
- option "Baptism"
|
||||||
|
- option "Bar/Bat Mitzvah"
|
||||||
|
- option "Bar/Pub Crawl"
|
||||||
|
- option "Baseball Tournament / Event"
|
||||||
|
- option "Basketball Tournament / Event"
|
||||||
|
- option "Battle of the Bands"
|
||||||
|
- option "Bazaar"
|
||||||
|
- option "Beauty Pageant"
|
||||||
|
- option "Beer Garden/Tent"
|
||||||
|
- option "Beer Mile"
|
||||||
|
- option "Billiards Tournament / Event"
|
||||||
|
- option "Bingo Games"
|
||||||
|
- option "Birthday Party"
|
||||||
|
- option "Block Parties/Street Closures/Street Fairs"
|
||||||
|
- option "BMX Tournament / Event"
|
||||||
|
- option "Boat Show (On Land)"
|
||||||
|
- option "Boat Show"
|
||||||
|
- option "Bocce Ball"
|
||||||
|
- option "Body Building Tournament / Event"
|
||||||
|
- option "Book Fair"
|
||||||
|
- option "Book Signing"
|
||||||
|
- option "Bowling Tournament / Event"
|
||||||
|
- option "Boxing Tournament / Event"
|
||||||
|
- option "Breakfast"
|
||||||
|
- option "Bridal Shower"
|
||||||
|
- option "Brunch - No Admission Charge - Invite Only"
|
||||||
|
- option "Business Meeting"
|
||||||
|
- option "Business Party"
|
||||||
|
- option "Cage Fight Tournament / Event"
|
||||||
|
- option "Cannabis Event"
|
||||||
|
- option "Car Show"
|
||||||
|
- option "Car Wash"
|
||||||
|
- option "Card Games"
|
||||||
|
- option "Casino Night"
|
||||||
|
- option "Cheerleading Tournament / Event"
|
||||||
|
- option "Chess Tournament"
|
||||||
|
- option "Church Service or Meeting"
|
||||||
|
- option "Cocktail Party - No Admission Charge - Invite Only"
|
||||||
|
- option "College Reunion"
|
||||||
|
- option "Comedy Show"
|
||||||
|
- option "Company Retreats"
|
||||||
|
- option "Concert - Choir"
|
||||||
|
- option "Concert - Classic Rock"
|
||||||
|
- option "Concert - Classical"
|
||||||
|
- option "Concert - Country"
|
||||||
|
- option "Concert - Doo-Wop"
|
||||||
|
- option "Concert - Electronic/EDM"
|
||||||
|
- option "Concert - Folk Guitar"
|
||||||
|
- option "Concert - Foreign"
|
||||||
|
- option "Concert - Heavy Metal"
|
||||||
|
- option "Concert - High Profile Performer"
|
||||||
|
- option "Concert - Hip Hop/Rap"
|
||||||
|
- option "Concert - Jazz"
|
||||||
|
- option "Concert - Music Festivals"
|
||||||
|
- option "Concert - Opera"
|
||||||
|
- option "Concert - Orchestra"
|
||||||
|
- option "Concert - Pop"
|
||||||
|
- option "Concert - R&B"
|
||||||
|
- option "Concert - Reggae"
|
||||||
|
- option "Concert - Rock"
|
||||||
|
- option "Concert - SKA"
|
||||||
|
- option "Concert - Soul"
|
||||||
|
- option "Concert - Symphony"
|
||||||
|
- option "Concert - Tribute Bands"
|
||||||
|
- option "Consumer Show"
|
||||||
|
- option "Cooking Competition"
|
||||||
|
- option "Corn Mazes"
|
||||||
|
- option "Cornhole Tournament / Event"
|
||||||
|
- option "Costume Contest"
|
||||||
|
- option "Craft Show"
|
||||||
|
- option "Cycling"
|
||||||
|
- option "Dance Competition"
|
||||||
|
- option "Dance Recital"
|
||||||
|
- option "Dance Team Tournament / Event"
|
||||||
|
- option "Debutante Ball"
|
||||||
|
- option "Demolition Derby"
|
||||||
|
- option "Dinner - No Admission Charge - Invite Only"
|
||||||
|
- option "Dirt Bike Tournament / Event"
|
||||||
|
- option "Dog Show"
|
||||||
|
- option "Drive-In Movie/Concert"
|
||||||
|
- option "Egg Hunt"
|
||||||
|
- option "Engagement Party"
|
||||||
|
- option "Exotic Dancer Event"
|
||||||
|
- option "Extreme Sporting Tournament / Event"
|
||||||
|
- option "Family Reunion"
|
||||||
|
- option "Farm Show"
|
||||||
|
- option "Farmer's Market"
|
||||||
|
- option "Fashion Show"
|
||||||
|
- option "Fencing Tournament / Event"
|
||||||
|
- option "Field Hockey Tournament / Event"
|
||||||
|
- option "Film Screenings"
|
||||||
|
- option "Film Shoot (In Studio)"
|
||||||
|
- option "First Communion"
|
||||||
|
- option "Fishing Tournament/Event"
|
||||||
|
- option "Flag Football Tournament / Event"
|
||||||
|
- option "Flea Market"
|
||||||
|
- option "Flower Show"
|
||||||
|
- option "Food Festival"
|
||||||
|
- option "Football Tournament / Event"
|
||||||
|
- option "Fraternity/Sorority Party"
|
||||||
|
- option "Frisbee Golf Tournament / Event"
|
||||||
|
- option "Fundraiser Dinner"
|
||||||
|
- option "Funeral Service"
|
||||||
|
- option "Gala with Seated Dinner"
|
||||||
|
- option "Garden Show"
|
||||||
|
- option "Gift Wrapping Party"
|
||||||
|
- option "Golf Tournament / Event"
|
||||||
|
- option "Gymnastics Tournament / Event"
|
||||||
|
- option "Haunted Houses"
|
||||||
|
- option "Health Fair"
|
||||||
|
- option "High School Graduation Party"
|
||||||
|
- option "High School Reunion"
|
||||||
|
- option "High School Graduation Ceremony"
|
||||||
|
- option "Holiday Character (Santa, Easter Bunny, etc.)"
|
||||||
|
- option "Holiday Party – No Admission Charge – Invite Only"
|
||||||
|
- option "Home and Garden Tour"
|
||||||
|
- option "Horse Show/Competition"
|
||||||
|
- option "Ice Hockey Tournament / Event"
|
||||||
|
- option "Ice Skating Show / Event"
|
||||||
|
- option "Indoor Convention"
|
||||||
|
- option "Indoor Tradeshow"
|
||||||
|
- option "Jewelry Show"
|
||||||
|
- option "Job Fair"
|
||||||
|
- option "Lacrosse Tournament / Event"
|
||||||
|
- option "Lecture"
|
||||||
|
- option "Livestock Auction"
|
||||||
|
- option "Luncheon"
|
||||||
|
- option "Magic Show"
|
||||||
|
- option "Marching Band Tournament / Event"
|
||||||
|
- option "Mardis Gras Party"
|
||||||
|
- option "Martial Arts Tournament / Event"
|
||||||
|
- option "Math Tournament"
|
||||||
|
- option "Medical Conference"
|
||||||
|
- option "Meeting"
|
||||||
|
- option "Memorial Service"
|
||||||
|
- option "Mixed Martial Arts Tournament / Event"
|
||||||
|
- option "Motocross"
|
||||||
|
- option "Motorcycle or Race Car On Road Competition"
|
||||||
|
- option "Motorcycle Run"
|
||||||
|
- option "Mud Bogs"
|
||||||
|
- option "New Year's Eve Party"
|
||||||
|
- option "Parade with Floats"
|
||||||
|
- option "Parade without Floats"
|
||||||
|
- option "Piano Recital"
|
||||||
|
- option "Pickleball Tournament / Event"
|
||||||
|
- option "Picnics"
|
||||||
|
- option "Pig Roast"
|
||||||
|
- option "Play Readings"
|
||||||
|
- option "Poetry Reading"
|
||||||
|
- option "Poker Runs"
|
||||||
|
- option "Political Rally"
|
||||||
|
- option "Prom"
|
||||||
|
- option "Quinceanera"
|
||||||
|
- option "Renaissance Fairs"
|
||||||
|
- option "Retirement Party"
|
||||||
|
- option "Road Race (13.2M or longer)"
|
||||||
|
- option "Road Race (Running only; 13.1M or less)"
|
||||||
|
- option "Rummage Sale"
|
||||||
|
- option "Seminar"
|
||||||
|
- option "Skateboarding Tournament / Event"
|
||||||
|
- option "Soccer Tournament / Event"
|
||||||
|
- option "Softball Tournament / Event"
|
||||||
|
- option "Spikeball Tournament / Event"
|
||||||
|
- option "Surfing Tournament / Event"
|
||||||
|
- option "Swimming Tournament / Event"
|
||||||
|
- option "Tap Dancing Show"
|
||||||
|
- option "Tennis Tournament / Event"
|
||||||
|
- option "Theatrical Production"
|
||||||
|
- option "Toy Drive"
|
||||||
|
- option "Track and Field Tournament / Event"
|
||||||
|
- option "Triathlon Tournament / Event"
|
||||||
|
- option "Trivia Night"
|
||||||
|
- option "Ultimate Frisbee Tournament / Event"
|
||||||
|
- option "Valentine's Day Party"
|
||||||
|
- option "Video Games Contests"
|
||||||
|
- option "Volleyball Tournament / Event"
|
||||||
|
- option "Voter Registration"
|
||||||
|
- option "Walk-a-thon Tournament / Event"
|
||||||
|
- option "Wedding Anniversary Party"
|
||||||
|
- option "Wedding Ceremony and/or Reception"
|
||||||
|
- option "Weightlifting Tournament / Event"
|
||||||
|
- option "Wrestling Tournament / Event"
|
||||||
|
- option "Yard Sale"
|
||||||
|
- option "Yoga Tournament / Event"
|
||||||
|
- option "Zumba Tournament / Event"
|
||||||
|
- generic [ref=e58]:
|
||||||
|
- generic [ref=e59]:
|
||||||
|
- text: Event Location
|
||||||
|
- generic [ref=e61]: "*"
|
||||||
|
- combobox "Event Location *" [ref=e63]:
|
||||||
|
- option [selected]
|
||||||
|
- option "Alabama"
|
||||||
|
- option "Alaska"
|
||||||
|
- option "Arizona"
|
||||||
|
- option "Arkansas"
|
||||||
|
- option "California"
|
||||||
|
- option "Colorado"
|
||||||
|
- option "Connecticut"
|
||||||
|
- option "Delaware"
|
||||||
|
- option "District of Columbia"
|
||||||
|
- option "Florida"
|
||||||
|
- option "Georgia"
|
||||||
|
- option "Hawaii"
|
||||||
|
- option "Idaho"
|
||||||
|
- option "Illinois"
|
||||||
|
- option "Indiana"
|
||||||
|
- option "Iowa"
|
||||||
|
- option "Kansas"
|
||||||
|
- option "Kentucky"
|
||||||
|
- option "Louisiana"
|
||||||
|
- option "Maine"
|
||||||
|
- option "Maryland"
|
||||||
|
- option "Massachusetts"
|
||||||
|
- option "Michigan"
|
||||||
|
- option "Minnesota"
|
||||||
|
- option "Mississippi"
|
||||||
|
- option "Missouri"
|
||||||
|
- option "Montana"
|
||||||
|
- option "Nebraska"
|
||||||
|
- option "Nevada"
|
||||||
|
- option "New Hampshire"
|
||||||
|
- option "New Jersey"
|
||||||
|
- option "New Mexico"
|
||||||
|
- option "New York"
|
||||||
|
- option "North Carolina"
|
||||||
|
- option "North Dakota"
|
||||||
|
- option "Ohio"
|
||||||
|
- option "Oklahoma"
|
||||||
|
- option "Oregon"
|
||||||
|
- option "Pennsylvania"
|
||||||
|
- option "Rhode Island"
|
||||||
|
- option "South Carolina"
|
||||||
|
- option "South Dakota"
|
||||||
|
- option "Tennessee"
|
||||||
|
- option "Texas"
|
||||||
|
- option "Utah"
|
||||||
|
- option "Vermont"
|
||||||
|
- option "Virginia"
|
||||||
|
- option "Washington"
|
||||||
|
- option "West Virginia"
|
||||||
|
- option "Wisconsin"
|
||||||
|
- option "Wyoming"
|
||||||
|
- generic [ref=e64]:
|
||||||
|
- generic [ref=e65]:
|
||||||
|
- text: Maximum Daily Attendance
|
||||||
|
- generic [ref=e67]: "*"
|
||||||
|
- spinbutton "Maximum Daily Attendance *" [ref=e69]
|
||||||
|
- generic [ref=e70]:
|
||||||
|
- generic [ref=e71]:
|
||||||
|
- text: Event Start Date
|
||||||
|
- generic [ref=e73]: "*"
|
||||||
|
- generic [ref=e74]:
|
||||||
|
- textbox "Event Start Date *" [ref=e75]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- generic [ref=e76]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=e77]:
|
||||||
|
- generic [ref=e78]:
|
||||||
|
- text: Event End Date
|
||||||
|
- generic [ref=e80]: "*"
|
||||||
|
- generic [ref=e81]:
|
||||||
|
- textbox "Event End Date *" [ref=e82]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- generic [ref=e83]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=e84]:
|
||||||
|
- generic [ref=e85]:
|
||||||
|
- text: Customer Email Address
|
||||||
|
- generic [ref=e87]: "*"
|
||||||
|
- textbox "Customer Email Address *" [ref=e89]
|
||||||
|
- button "Submit" [ref=e91] [cursor=pointer]
|
||||||
|
- paragraph
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=e92]:
|
||||||
|
- complementary [ref=e97]:
|
||||||
|
- list [ref=e99]:
|
||||||
|
- listitem [ref=e100]:
|
||||||
|
- link "Home" [ref=e101] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- listitem [ref=e102]:
|
||||||
|
- link "Blog" [ref=e103] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/blog
|
||||||
|
- listitem [ref=e104]:
|
||||||
|
- link "Contact" [ref=e105] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- contentinfo "Site" [ref=e108]:
|
||||||
|
- generic [ref=e110]:
|
||||||
|
- text: © 2026 HUB Insurance • Built with
|
||||||
|
- link "GeneratePress" [ref=e111] [cursor=pointer]:
|
||||||
|
- /url: https://generatepress.com
|
||||||
@@ -0,0 +1,369 @@
|
|||||||
|
- generic [ref=e1]:
|
||||||
|
- link "Skip to content" [ref=e2] [cursor=pointer]:
|
||||||
|
- /url: "#content"
|
||||||
|
- banner "Site" [ref=e3]:
|
||||||
|
- generic [ref=e4]:
|
||||||
|
- link "HUB Insurance" [ref=e6] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- img "HUB Insurance" [ref=e7]
|
||||||
|
- navigation "Primary" [ref=e8]:
|
||||||
|
- list [ref=e11]:
|
||||||
|
- listitem [ref=e12]:
|
||||||
|
- link "About" [ref=e13] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/about
|
||||||
|
- listitem [ref=e14]:
|
||||||
|
- link "Contact" [ref=e15] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- listitem [ref=e16]:
|
||||||
|
- link "Get a Quote" [ref=e17] [cursor=pointer]:
|
||||||
|
- /url: "#get-a-quote"
|
||||||
|
- generic [ref=e19]:
|
||||||
|
- heading "Special Event Insurance" [level=1] [ref=e20]:
|
||||||
|
- text: Special
|
||||||
|
- emphasis [ref=e21]: Event
|
||||||
|
- text: Insurance
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=e22]: "{Hero Content} Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||||
|
- list [ref=e23]:
|
||||||
|
- listitem [ref=e24]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e25]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e26]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e27]: Lorem ipsum dolor
|
||||||
|
- paragraph
|
||||||
|
- link "Hero CTA Lorem" [ref=e28] [cursor=pointer]:
|
||||||
|
- /url: https://www.getfused.com
|
||||||
|
- main [ref=e32]:
|
||||||
|
- generic [ref=e33]:
|
||||||
|
- generic [ref=e34]:
|
||||||
|
- generic [ref=e35]:
|
||||||
|
- paragraph [ref=e36]: How it Works
|
||||||
|
- heading "Three Simple Steps" [level=2] [ref=e37]
|
||||||
|
- generic [ref=e38]:
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=e39]:
|
||||||
|
- generic [ref=e40]:
|
||||||
|
- heading "Start a Quote" [level=2] [ref=e41]
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=e42]: An asterisk (*) indicates a required field.
|
||||||
|
- generic [ref=e43]:
|
||||||
|
- generic [ref=e45]:
|
||||||
|
- generic [ref=e46]:
|
||||||
|
- generic [ref=e47]:
|
||||||
|
- text: Event Role
|
||||||
|
- generic [ref=e49]: "*"
|
||||||
|
- combobox "Event Role *" [ref=e51]:
|
||||||
|
- option
|
||||||
|
- option "Event Host or Organizer" [selected]
|
||||||
|
- option "Vendor, Exhibitor or Subcontractor"
|
||||||
|
- option "Performer, Entertainer or DJ"
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- generic [ref=e53]:
|
||||||
|
- text: Activity / Event Type
|
||||||
|
- generic [ref=e55]: "*"
|
||||||
|
- combobox "Activity / Event Type *" [ref=e57]:
|
||||||
|
- option
|
||||||
|
- option "Animal Adoption Event"
|
||||||
|
- option "Animal Shows"
|
||||||
|
- option "Antique Show"
|
||||||
|
- option "Art Festival"
|
||||||
|
- option "Art Show"
|
||||||
|
- option "Auction"
|
||||||
|
- option "Award Presentation"
|
||||||
|
- option "Baby Shower"
|
||||||
|
- option "Bachelor Party"
|
||||||
|
- option "Bachelorette Party"
|
||||||
|
- option "Badminton Tournament / Event"
|
||||||
|
- option "Bake Sale"
|
||||||
|
- option "Ballet"
|
||||||
|
- option "Banquet"
|
||||||
|
- option "Baptism"
|
||||||
|
- option "Bar/Bat Mitzvah"
|
||||||
|
- option "Bar/Pub Crawl"
|
||||||
|
- option "Baseball Tournament / Event"
|
||||||
|
- option "Basketball Tournament / Event"
|
||||||
|
- option "Battle of the Bands"
|
||||||
|
- option "Bazaar"
|
||||||
|
- option "Beauty Pageant"
|
||||||
|
- option "Beer Garden/Tent"
|
||||||
|
- option "Beer Mile"
|
||||||
|
- option "Billiards Tournament / Event"
|
||||||
|
- option "Bingo Games"
|
||||||
|
- option "Birthday Party" [selected]
|
||||||
|
- option "Block Parties/Street Closures/Street Fairs"
|
||||||
|
- option "BMX Tournament / Event"
|
||||||
|
- option "Boat Show (On Land)"
|
||||||
|
- option "Boat Show"
|
||||||
|
- option "Bocce Ball"
|
||||||
|
- option "Body Building Tournament / Event"
|
||||||
|
- option "Book Fair"
|
||||||
|
- option "Book Signing"
|
||||||
|
- option "Bowling Tournament / Event"
|
||||||
|
- option "Boxing Tournament / Event"
|
||||||
|
- option "Breakfast"
|
||||||
|
- option "Bridal Shower"
|
||||||
|
- option "Brunch - No Admission Charge - Invite Only"
|
||||||
|
- option "Business Meeting"
|
||||||
|
- option "Business Party"
|
||||||
|
- option "Cage Fight Tournament / Event"
|
||||||
|
- option "Cannabis Event"
|
||||||
|
- option "Car Show"
|
||||||
|
- option "Car Wash"
|
||||||
|
- option "Card Games"
|
||||||
|
- option "Casino Night"
|
||||||
|
- option "Cheerleading Tournament / Event"
|
||||||
|
- option "Chess Tournament"
|
||||||
|
- option "Church Service or Meeting"
|
||||||
|
- option "Cocktail Party - No Admission Charge - Invite Only"
|
||||||
|
- option "College Reunion"
|
||||||
|
- option "Comedy Show"
|
||||||
|
- option "Company Retreats"
|
||||||
|
- option "Concert - Choir"
|
||||||
|
- option "Concert - Classic Rock"
|
||||||
|
- option "Concert - Classical"
|
||||||
|
- option "Concert - Country"
|
||||||
|
- option "Concert - Doo-Wop"
|
||||||
|
- option "Concert - Electronic/EDM"
|
||||||
|
- option "Concert - Folk Guitar"
|
||||||
|
- option "Concert - Foreign"
|
||||||
|
- option "Concert - Heavy Metal"
|
||||||
|
- option "Concert - High Profile Performer"
|
||||||
|
- option "Concert - Hip Hop/Rap"
|
||||||
|
- option "Concert - Jazz"
|
||||||
|
- option "Concert - Music Festivals"
|
||||||
|
- option "Concert - Opera"
|
||||||
|
- option "Concert - Orchestra"
|
||||||
|
- option "Concert - Pop"
|
||||||
|
- option "Concert - R&B"
|
||||||
|
- option "Concert - Reggae"
|
||||||
|
- option "Concert - Rock"
|
||||||
|
- option "Concert - SKA"
|
||||||
|
- option "Concert - Soul"
|
||||||
|
- option "Concert - Symphony"
|
||||||
|
- option "Concert - Tribute Bands"
|
||||||
|
- option "Consumer Show"
|
||||||
|
- option "Cooking Competition"
|
||||||
|
- option "Corn Mazes"
|
||||||
|
- option "Cornhole Tournament / Event"
|
||||||
|
- option "Costume Contest"
|
||||||
|
- option "Craft Show"
|
||||||
|
- option "Cycling"
|
||||||
|
- option "Dance Competition"
|
||||||
|
- option "Dance Recital"
|
||||||
|
- option "Dance Team Tournament / Event"
|
||||||
|
- option "Debutante Ball"
|
||||||
|
- option "Demolition Derby"
|
||||||
|
- option "Dinner - No Admission Charge - Invite Only"
|
||||||
|
- option "Dirt Bike Tournament / Event"
|
||||||
|
- option "Dog Show"
|
||||||
|
- option "Drive-In Movie/Concert"
|
||||||
|
- option "Egg Hunt"
|
||||||
|
- option "Engagement Party"
|
||||||
|
- option "Exotic Dancer Event"
|
||||||
|
- option "Extreme Sporting Tournament / Event"
|
||||||
|
- option "Family Reunion"
|
||||||
|
- option "Farm Show"
|
||||||
|
- option "Farmer's Market"
|
||||||
|
- option "Fashion Show"
|
||||||
|
- option "Fencing Tournament / Event"
|
||||||
|
- option "Field Hockey Tournament / Event"
|
||||||
|
- option "Film Screenings"
|
||||||
|
- option "Film Shoot (In Studio)"
|
||||||
|
- option "First Communion"
|
||||||
|
- option "Fishing Tournament/Event"
|
||||||
|
- option "Flag Football Tournament / Event"
|
||||||
|
- option "Flea Market"
|
||||||
|
- option "Flower Show"
|
||||||
|
- option "Food Festival"
|
||||||
|
- option "Football Tournament / Event"
|
||||||
|
- option "Fraternity/Sorority Party"
|
||||||
|
- option "Frisbee Golf Tournament / Event"
|
||||||
|
- option "Fundraiser Dinner"
|
||||||
|
- option "Funeral Service"
|
||||||
|
- option "Gala with Seated Dinner"
|
||||||
|
- option "Garden Show"
|
||||||
|
- option "Gift Wrapping Party"
|
||||||
|
- option "Golf Tournament / Event"
|
||||||
|
- option "Gymnastics Tournament / Event"
|
||||||
|
- option "Haunted Houses"
|
||||||
|
- option "Health Fair"
|
||||||
|
- option "High School Graduation Party"
|
||||||
|
- option "High School Reunion"
|
||||||
|
- option "High School Graduation Ceremony"
|
||||||
|
- option "Holiday Character (Santa, Easter Bunny, etc.)"
|
||||||
|
- option "Holiday Party – No Admission Charge – Invite Only"
|
||||||
|
- option "Home and Garden Tour"
|
||||||
|
- option "Horse Show/Competition"
|
||||||
|
- option "Ice Hockey Tournament / Event"
|
||||||
|
- option "Ice Skating Show / Event"
|
||||||
|
- option "Indoor Convention"
|
||||||
|
- option "Indoor Tradeshow"
|
||||||
|
- option "Jewelry Show"
|
||||||
|
- option "Job Fair"
|
||||||
|
- option "Lacrosse Tournament / Event"
|
||||||
|
- option "Lecture"
|
||||||
|
- option "Livestock Auction"
|
||||||
|
- option "Luncheon"
|
||||||
|
- option "Magic Show"
|
||||||
|
- option "Marching Band Tournament / Event"
|
||||||
|
- option "Mardis Gras Party"
|
||||||
|
- option "Martial Arts Tournament / Event"
|
||||||
|
- option "Math Tournament"
|
||||||
|
- option "Medical Conference"
|
||||||
|
- option "Meeting"
|
||||||
|
- option "Memorial Service"
|
||||||
|
- option "Mixed Martial Arts Tournament / Event"
|
||||||
|
- option "Motocross"
|
||||||
|
- option "Motorcycle or Race Car On Road Competition"
|
||||||
|
- option "Motorcycle Run"
|
||||||
|
- option "Mud Bogs"
|
||||||
|
- option "New Year's Eve Party"
|
||||||
|
- option "Parade with Floats"
|
||||||
|
- option "Parade without Floats"
|
||||||
|
- option "Piano Recital"
|
||||||
|
- option "Pickleball Tournament / Event"
|
||||||
|
- option "Picnics"
|
||||||
|
- option "Pig Roast"
|
||||||
|
- option "Play Readings"
|
||||||
|
- option "Poetry Reading"
|
||||||
|
- option "Poker Runs"
|
||||||
|
- option "Political Rally"
|
||||||
|
- option "Prom"
|
||||||
|
- option "Quinceanera"
|
||||||
|
- option "Renaissance Fairs"
|
||||||
|
- option "Retirement Party"
|
||||||
|
- option "Road Race (13.2M or longer)"
|
||||||
|
- option "Road Race (Running only; 13.1M or less)"
|
||||||
|
- option "Rummage Sale"
|
||||||
|
- option "Seminar"
|
||||||
|
- option "Skateboarding Tournament / Event"
|
||||||
|
- option "Soccer Tournament / Event"
|
||||||
|
- option "Softball Tournament / Event"
|
||||||
|
- option "Spikeball Tournament / Event"
|
||||||
|
- option "Surfing Tournament / Event"
|
||||||
|
- option "Swimming Tournament / Event"
|
||||||
|
- option "Tap Dancing Show"
|
||||||
|
- option "Tennis Tournament / Event"
|
||||||
|
- option "Theatrical Production"
|
||||||
|
- option "Toy Drive"
|
||||||
|
- option "Track and Field Tournament / Event"
|
||||||
|
- option "Triathlon Tournament / Event"
|
||||||
|
- option "Trivia Night"
|
||||||
|
- option "Ultimate Frisbee Tournament / Event"
|
||||||
|
- option "Valentine's Day Party"
|
||||||
|
- option "Video Games Contests"
|
||||||
|
- option "Volleyball Tournament / Event"
|
||||||
|
- option "Voter Registration"
|
||||||
|
- option "Walk-a-thon Tournament / Event"
|
||||||
|
- option "Wedding Anniversary Party"
|
||||||
|
- option "Wedding Ceremony and/or Reception"
|
||||||
|
- option "Weightlifting Tournament / Event"
|
||||||
|
- option "Wrestling Tournament / Event"
|
||||||
|
- option "Yard Sale"
|
||||||
|
- option "Yoga Tournament / Event"
|
||||||
|
- option "Zumba Tournament / Event"
|
||||||
|
- generic [ref=e58]:
|
||||||
|
- generic [ref=e59]:
|
||||||
|
- text: Event Location
|
||||||
|
- generic [ref=e61]: "*"
|
||||||
|
- combobox "Event Location *" [ref=e63]:
|
||||||
|
- option
|
||||||
|
- option "Alabama"
|
||||||
|
- option "Alaska"
|
||||||
|
- option "Arizona"
|
||||||
|
- option "Arkansas"
|
||||||
|
- option "California"
|
||||||
|
- option "Colorado"
|
||||||
|
- option "Connecticut"
|
||||||
|
- option "Delaware"
|
||||||
|
- option "District of Columbia"
|
||||||
|
- option "Florida"
|
||||||
|
- option "Georgia"
|
||||||
|
- option "Hawaii"
|
||||||
|
- option "Idaho"
|
||||||
|
- option "Illinois"
|
||||||
|
- option "Indiana"
|
||||||
|
- option "Iowa"
|
||||||
|
- option "Kansas"
|
||||||
|
- option "Kentucky"
|
||||||
|
- option "Louisiana"
|
||||||
|
- option "Maine"
|
||||||
|
- option "Maryland"
|
||||||
|
- option "Massachusetts"
|
||||||
|
- option "Michigan"
|
||||||
|
- option "Minnesota"
|
||||||
|
- option "Mississippi"
|
||||||
|
- option "Missouri"
|
||||||
|
- option "Montana"
|
||||||
|
- option "Nebraska"
|
||||||
|
- option "Nevada"
|
||||||
|
- option "New Hampshire"
|
||||||
|
- option "New Jersey"
|
||||||
|
- option "New Mexico"
|
||||||
|
- option "New York" [selected]
|
||||||
|
- option "North Carolina"
|
||||||
|
- option "North Dakota"
|
||||||
|
- option "Ohio"
|
||||||
|
- option "Oklahoma"
|
||||||
|
- option "Oregon"
|
||||||
|
- option "Pennsylvania"
|
||||||
|
- option "Rhode Island"
|
||||||
|
- option "South Carolina"
|
||||||
|
- option "South Dakota"
|
||||||
|
- option "Tennessee"
|
||||||
|
- option "Texas"
|
||||||
|
- option "Utah"
|
||||||
|
- option "Vermont"
|
||||||
|
- option "Virginia"
|
||||||
|
- option "Washington"
|
||||||
|
- option "West Virginia"
|
||||||
|
- option "Wisconsin"
|
||||||
|
- option "Wyoming"
|
||||||
|
- generic [ref=e64]:
|
||||||
|
- generic [ref=e65]:
|
||||||
|
- text: Maximum Daily Attendance
|
||||||
|
- generic [ref=e67]: "*"
|
||||||
|
- spinbutton "Maximum Daily Attendance *" [ref=e69]: "100"
|
||||||
|
- generic [ref=e70]:
|
||||||
|
- generic [ref=e71]:
|
||||||
|
- text: Event Start Date
|
||||||
|
- generic [ref=e73]: "*"
|
||||||
|
- generic [ref=e74]:
|
||||||
|
- textbox "Event Start Date *" [ref=e75]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- text: 2026-09-01
|
||||||
|
- generic [ref=e76]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=e77]:
|
||||||
|
- generic [ref=e78]:
|
||||||
|
- text: Event End Date
|
||||||
|
- generic [ref=e80]: "*"
|
||||||
|
- generic [ref=e81]:
|
||||||
|
- textbox "Event End Date *" [ref=e82]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- text: 2026-09-03
|
||||||
|
- generic [ref=e83]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=e84]:
|
||||||
|
- generic [ref=e85]:
|
||||||
|
- text: Customer Email Address
|
||||||
|
- generic [ref=e87]: "*"
|
||||||
|
- textbox "Customer Email Address *" [ref=e89]: instanda-smoke-20260703@example.com
|
||||||
|
- button "Submit" [active] [ref=e91] [cursor=pointer]
|
||||||
|
- paragraph
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=e92]:
|
||||||
|
- complementary [ref=e97]:
|
||||||
|
- list [ref=e99]:
|
||||||
|
- listitem [ref=e100]:
|
||||||
|
- link "Home" [ref=e101] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- listitem [ref=e102]:
|
||||||
|
- link "Blog" [ref=e103] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/blog
|
||||||
|
- listitem [ref=e104]:
|
||||||
|
- link "Contact" [ref=e105] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- contentinfo "Site" [ref=e108]:
|
||||||
|
- generic [ref=e110]:
|
||||||
|
- text: © 2026 HUB Insurance • Built with
|
||||||
|
- link "GeneratePress" [ref=e111] [cursor=pointer]:
|
||||||
|
- /url: https://generatepress.com
|
||||||
|
- text:
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
- generic [ref=e1]:
|
||||||
|
- link "Skip to content" [ref=e2] [cursor=pointer]:
|
||||||
|
- /url: "#content"
|
||||||
|
- banner "Site" [ref=e3]:
|
||||||
|
- generic [ref=e4]:
|
||||||
|
- link "HUB Insurance" [ref=e6] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- img "HUB Insurance" [ref=e7]
|
||||||
|
- navigation "Primary" [ref=e8]:
|
||||||
|
- list [ref=e11]:
|
||||||
|
- listitem [ref=e12]:
|
||||||
|
- link "About" [ref=e13] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/about
|
||||||
|
- listitem [ref=e14]:
|
||||||
|
- link "Contact" [ref=e15] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- listitem [ref=e16]:
|
||||||
|
- link "Get a Quote" [ref=e17] [cursor=pointer]:
|
||||||
|
- /url: "#get-a-quote"
|
||||||
|
- generic [ref=e19]:
|
||||||
|
- heading "Special Event Insurance" [level=1] [ref=e20]:
|
||||||
|
- text: Special
|
||||||
|
- emphasis [ref=e21]: Event
|
||||||
|
- text: Insurance
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=e22]: "{Hero Content} Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||||
|
- list [ref=e23]:
|
||||||
|
- listitem [ref=e24]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e25]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e26]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e27]: Lorem ipsum dolor
|
||||||
|
- paragraph
|
||||||
|
- link "Hero CTA Lorem" [ref=e28] [cursor=pointer]:
|
||||||
|
- /url: https://www.getfused.com
|
||||||
|
- main [ref=e32]:
|
||||||
|
- generic [ref=e33]:
|
||||||
|
- generic [ref=e34]:
|
||||||
|
- generic [ref=e35]:
|
||||||
|
- paragraph [ref=e36]: How it Works
|
||||||
|
- heading "Three Simple Steps" [level=2] [ref=e37]
|
||||||
|
- generic [ref=e38]:
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=e39]:
|
||||||
|
- generic [active] [ref=e115]:
|
||||||
|
- text: There was a problem with your submission. Please review the fields below.
|
||||||
|
- list [ref=e116]:
|
||||||
|
- listitem [ref=e117]:
|
||||||
|
- 'link "Customer Email Address: The email address entered is invalid." [ref=e118] [cursor=pointer]':
|
||||||
|
- /url: "#field_5_10"
|
||||||
|
- generic [ref=e119]:
|
||||||
|
- heading "Start a Quote" [level=2] [ref=e120]
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=e121]: An asterisk (*) indicates a required field.
|
||||||
|
- generic [ref=e122]:
|
||||||
|
- generic [ref=e124]:
|
||||||
|
- generic [ref=e125]:
|
||||||
|
- generic [ref=e126]:
|
||||||
|
- text: Event Role
|
||||||
|
- generic [ref=e128]: "*"
|
||||||
|
- combobox "Event Role *" [ref=e130]:
|
||||||
|
- option
|
||||||
|
- option "Event Host or Organizer" [selected]
|
||||||
|
- option "Vendor, Exhibitor or Subcontractor"
|
||||||
|
- option "Performer, Entertainer or DJ"
|
||||||
|
- generic [ref=e131]:
|
||||||
|
- generic [ref=e132]:
|
||||||
|
- text: Activity / Event Type
|
||||||
|
- generic [ref=e134]: "*"
|
||||||
|
- combobox "Activity / Event Type *" [ref=e136]:
|
||||||
|
- option
|
||||||
|
- option "Animal Adoption Event"
|
||||||
|
- option "Animal Shows"
|
||||||
|
- option "Antique Show"
|
||||||
|
- option "Art Festival"
|
||||||
|
- option "Art Show"
|
||||||
|
- option "Auction"
|
||||||
|
- option "Award Presentation"
|
||||||
|
- option "Baby Shower"
|
||||||
|
- option "Bachelor Party"
|
||||||
|
- option "Bachelorette Party"
|
||||||
|
- option "Badminton Tournament / Event"
|
||||||
|
- option "Bake Sale"
|
||||||
|
- option "Ballet"
|
||||||
|
- option "Banquet"
|
||||||
|
- option "Baptism"
|
||||||
|
- option "Bar/Bat Mitzvah"
|
||||||
|
- option "Bar/Pub Crawl"
|
||||||
|
- option "Baseball Tournament / Event"
|
||||||
|
- option "Basketball Tournament / Event"
|
||||||
|
- option "Battle of the Bands"
|
||||||
|
- option "Bazaar"
|
||||||
|
- option "Beauty Pageant"
|
||||||
|
- option "Beer Garden/Tent"
|
||||||
|
- option "Beer Mile"
|
||||||
|
- option "Billiards Tournament / Event"
|
||||||
|
- option "Bingo Games"
|
||||||
|
- option "Birthday Party" [selected]
|
||||||
|
- option "Block Parties/Street Closures/Street Fairs"
|
||||||
|
- option "BMX Tournament / Event"
|
||||||
|
- option "Boat Show (On Land)"
|
||||||
|
- option "Boat Show"
|
||||||
|
- option "Bocce Ball"
|
||||||
|
- option "Body Building Tournament / Event"
|
||||||
|
- option "Book Fair"
|
||||||
|
- option "Book Signing"
|
||||||
|
- option "Bowling Tournament / Event"
|
||||||
|
- option "Boxing Tournament / Event"
|
||||||
|
- option "Breakfast"
|
||||||
|
- option "Bridal Shower"
|
||||||
|
- option "Brunch - No Admission Charge - Invite Only"
|
||||||
|
- option "Business Meeting"
|
||||||
|
- option "Business Party"
|
||||||
|
- option "Cage Fight Tournament / Event"
|
||||||
|
- option "Cannabis Event"
|
||||||
|
- option "Car Show"
|
||||||
|
- option "Car Wash"
|
||||||
|
- option "Card Games"
|
||||||
|
- option "Casino Night"
|
||||||
|
- option "Cheerleading Tournament / Event"
|
||||||
|
- option "Chess Tournament"
|
||||||
|
- option "Church Service or Meeting"
|
||||||
|
- option "Cocktail Party - No Admission Charge - Invite Only"
|
||||||
|
- option "College Reunion"
|
||||||
|
- option "Comedy Show"
|
||||||
|
- option "Company Retreats"
|
||||||
|
- option "Concert - Choir"
|
||||||
|
- option "Concert - Classic Rock"
|
||||||
|
- option "Concert - Classical"
|
||||||
|
- option "Concert - Country"
|
||||||
|
- option "Concert - Doo-Wop"
|
||||||
|
- option "Concert - Electronic/EDM"
|
||||||
|
- option "Concert - Folk Guitar"
|
||||||
|
- option "Concert - Foreign"
|
||||||
|
- option "Concert - Heavy Metal"
|
||||||
|
- option "Concert - High Profile Performer"
|
||||||
|
- option "Concert - Hip Hop/Rap"
|
||||||
|
- option "Concert - Jazz"
|
||||||
|
- option "Concert - Music Festivals"
|
||||||
|
- option "Concert - Opera"
|
||||||
|
- option "Concert - Orchestra"
|
||||||
|
- option "Concert - Pop"
|
||||||
|
- option "Concert - R&B"
|
||||||
|
- option "Concert - Reggae"
|
||||||
|
- option "Concert - Rock"
|
||||||
|
- option "Concert - SKA"
|
||||||
|
- option "Concert - Soul"
|
||||||
|
- option "Concert - Symphony"
|
||||||
|
- option "Concert - Tribute Bands"
|
||||||
|
- option "Consumer Show"
|
||||||
|
- option "Cooking Competition"
|
||||||
|
- option "Corn Mazes"
|
||||||
|
- option "Cornhole Tournament / Event"
|
||||||
|
- option "Costume Contest"
|
||||||
|
- option "Craft Show"
|
||||||
|
- option "Cycling"
|
||||||
|
- option "Dance Competition"
|
||||||
|
- option "Dance Recital"
|
||||||
|
- option "Dance Team Tournament / Event"
|
||||||
|
- option "Debutante Ball"
|
||||||
|
- option "Demolition Derby"
|
||||||
|
- option "Dinner - No Admission Charge - Invite Only"
|
||||||
|
- option "Dirt Bike Tournament / Event"
|
||||||
|
- option "Dog Show"
|
||||||
|
- option "Drive-In Movie/Concert"
|
||||||
|
- option "Egg Hunt"
|
||||||
|
- option "Engagement Party"
|
||||||
|
- option "Exotic Dancer Event"
|
||||||
|
- option "Extreme Sporting Tournament / Event"
|
||||||
|
- option "Family Reunion"
|
||||||
|
- option "Farm Show"
|
||||||
|
- option "Farmer's Market"
|
||||||
|
- option "Fashion Show"
|
||||||
|
- option "Fencing Tournament / Event"
|
||||||
|
- option "Field Hockey Tournament / Event"
|
||||||
|
- option "Film Screenings"
|
||||||
|
- option "Film Shoot (In Studio)"
|
||||||
|
- option "First Communion"
|
||||||
|
- option "Fishing Tournament/Event"
|
||||||
|
- option "Flag Football Tournament / Event"
|
||||||
|
- option "Flea Market"
|
||||||
|
- option "Flower Show"
|
||||||
|
- option "Food Festival"
|
||||||
|
- option "Football Tournament / Event"
|
||||||
|
- option "Fraternity/Sorority Party"
|
||||||
|
- option "Frisbee Golf Tournament / Event"
|
||||||
|
- option "Fundraiser Dinner"
|
||||||
|
- option "Funeral Service"
|
||||||
|
- option "Gala with Seated Dinner"
|
||||||
|
- option "Garden Show"
|
||||||
|
- option "Gift Wrapping Party"
|
||||||
|
- option "Golf Tournament / Event"
|
||||||
|
- option "Gymnastics Tournament / Event"
|
||||||
|
- option "Haunted Houses"
|
||||||
|
- option "Health Fair"
|
||||||
|
- option "High School Graduation Party"
|
||||||
|
- option "High School Reunion"
|
||||||
|
- option "High School Graduation Ceremony"
|
||||||
|
- option "Holiday Character (Santa, Easter Bunny, etc.)"
|
||||||
|
- option "Holiday Party – No Admission Charge – Invite Only"
|
||||||
|
- option "Home and Garden Tour"
|
||||||
|
- option "Horse Show/Competition"
|
||||||
|
- option "Ice Hockey Tournament / Event"
|
||||||
|
- option "Ice Skating Show / Event"
|
||||||
|
- option "Indoor Convention"
|
||||||
|
- option "Indoor Tradeshow"
|
||||||
|
- option "Jewelry Show"
|
||||||
|
- option "Job Fair"
|
||||||
|
- option "Lacrosse Tournament / Event"
|
||||||
|
- option "Lecture"
|
||||||
|
- option "Livestock Auction"
|
||||||
|
- option "Luncheon"
|
||||||
|
- option "Magic Show"
|
||||||
|
- option "Marching Band Tournament / Event"
|
||||||
|
- option "Mardis Gras Party"
|
||||||
|
- option "Martial Arts Tournament / Event"
|
||||||
|
- option "Math Tournament"
|
||||||
|
- option "Medical Conference"
|
||||||
|
- option "Meeting"
|
||||||
|
- option "Memorial Service"
|
||||||
|
- option "Mixed Martial Arts Tournament / Event"
|
||||||
|
- option "Motocross"
|
||||||
|
- option "Motorcycle or Race Car On Road Competition"
|
||||||
|
- option "Motorcycle Run"
|
||||||
|
- option "Mud Bogs"
|
||||||
|
- option "New Year's Eve Party"
|
||||||
|
- option "Parade with Floats"
|
||||||
|
- option "Parade without Floats"
|
||||||
|
- option "Piano Recital"
|
||||||
|
- option "Pickleball Tournament / Event"
|
||||||
|
- option "Picnics"
|
||||||
|
- option "Pig Roast"
|
||||||
|
- option "Play Readings"
|
||||||
|
- option "Poetry Reading"
|
||||||
|
- option "Poker Runs"
|
||||||
|
- option "Political Rally"
|
||||||
|
- option "Prom"
|
||||||
|
- option "Quinceanera"
|
||||||
|
- option "Renaissance Fairs"
|
||||||
|
- option "Retirement Party"
|
||||||
|
- option "Road Race (13.2M or longer)"
|
||||||
|
- option "Road Race (Running only; 13.1M or less)"
|
||||||
|
- option "Rummage Sale"
|
||||||
|
- option "Seminar"
|
||||||
|
- option "Skateboarding Tournament / Event"
|
||||||
|
- option "Soccer Tournament / Event"
|
||||||
|
- option "Softball Tournament / Event"
|
||||||
|
- option "Spikeball Tournament / Event"
|
||||||
|
- option "Surfing Tournament / Event"
|
||||||
|
- option "Swimming Tournament / Event"
|
||||||
|
- option "Tap Dancing Show"
|
||||||
|
- option "Tennis Tournament / Event"
|
||||||
|
- option "Theatrical Production"
|
||||||
|
- option "Toy Drive"
|
||||||
|
- option "Track and Field Tournament / Event"
|
||||||
|
- option "Triathlon Tournament / Event"
|
||||||
|
- option "Trivia Night"
|
||||||
|
- option "Ultimate Frisbee Tournament / Event"
|
||||||
|
- option "Valentine's Day Party"
|
||||||
|
- option "Video Games Contests"
|
||||||
|
- option "Volleyball Tournament / Event"
|
||||||
|
- option "Voter Registration"
|
||||||
|
- option "Walk-a-thon Tournament / Event"
|
||||||
|
- option "Wedding Anniversary Party"
|
||||||
|
- option "Wedding Ceremony and/or Reception"
|
||||||
|
- option "Weightlifting Tournament / Event"
|
||||||
|
- option "Wrestling Tournament / Event"
|
||||||
|
- option "Yard Sale"
|
||||||
|
- option "Yoga Tournament / Event"
|
||||||
|
- option "Zumba Tournament / Event"
|
||||||
|
- generic [ref=e137]:
|
||||||
|
- generic [ref=e138]:
|
||||||
|
- text: Event Location
|
||||||
|
- generic [ref=e140]: "*"
|
||||||
|
- combobox "Event Location *" [ref=e142]:
|
||||||
|
- option
|
||||||
|
- option "Alabama"
|
||||||
|
- option "Alaska"
|
||||||
|
- option "Arizona"
|
||||||
|
- option "Arkansas"
|
||||||
|
- option "California"
|
||||||
|
- option "Colorado"
|
||||||
|
- option "Connecticut"
|
||||||
|
- option "Delaware"
|
||||||
|
- option "District of Columbia"
|
||||||
|
- option "Florida"
|
||||||
|
- option "Georgia"
|
||||||
|
- option "Hawaii"
|
||||||
|
- option "Idaho"
|
||||||
|
- option "Illinois"
|
||||||
|
- option "Indiana"
|
||||||
|
- option "Iowa"
|
||||||
|
- option "Kansas"
|
||||||
|
- option "Kentucky"
|
||||||
|
- option "Louisiana"
|
||||||
|
- option "Maine"
|
||||||
|
- option "Maryland"
|
||||||
|
- option "Massachusetts"
|
||||||
|
- option "Michigan"
|
||||||
|
- option "Minnesota"
|
||||||
|
- option "Mississippi"
|
||||||
|
- option "Missouri"
|
||||||
|
- option "Montana"
|
||||||
|
- option "Nebraska"
|
||||||
|
- option "Nevada"
|
||||||
|
- option "New Hampshire"
|
||||||
|
- option "New Jersey"
|
||||||
|
- option "New Mexico"
|
||||||
|
- option "New York" [selected]
|
||||||
|
- option "North Carolina"
|
||||||
|
- option "North Dakota"
|
||||||
|
- option "Ohio"
|
||||||
|
- option "Oklahoma"
|
||||||
|
- option "Oregon"
|
||||||
|
- option "Pennsylvania"
|
||||||
|
- option "Rhode Island"
|
||||||
|
- option "South Carolina"
|
||||||
|
- option "South Dakota"
|
||||||
|
- option "Tennessee"
|
||||||
|
- option "Texas"
|
||||||
|
- option "Utah"
|
||||||
|
- option "Vermont"
|
||||||
|
- option "Virginia"
|
||||||
|
- option "Washington"
|
||||||
|
- option "West Virginia"
|
||||||
|
- option "Wisconsin"
|
||||||
|
- option "Wyoming"
|
||||||
|
- generic [ref=e143]:
|
||||||
|
- generic [ref=e144]:
|
||||||
|
- text: Maximum Daily Attendance
|
||||||
|
- generic [ref=e146]: "*"
|
||||||
|
- spinbutton "Maximum Daily Attendance *" [ref=e148]: "100"
|
||||||
|
- generic [ref=e149]:
|
||||||
|
- generic [ref=e150]:
|
||||||
|
- text: Event Start Date
|
||||||
|
- generic [ref=e152]: "*"
|
||||||
|
- generic [ref=e153]:
|
||||||
|
- textbox "Event Start Date *" [ref=e154]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- text: 2026-09-01
|
||||||
|
- generic [ref=e155]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=e156]:
|
||||||
|
- generic [ref=e157]:
|
||||||
|
- text: Event End Date
|
||||||
|
- generic [ref=e159]: "*"
|
||||||
|
- generic [ref=e160]:
|
||||||
|
- textbox "Event End Date *" [ref=e161]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- text: 2026-09-03
|
||||||
|
- generic [ref=e162]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=e163]:
|
||||||
|
- generic [ref=e164]:
|
||||||
|
- text: Customer Email Address
|
||||||
|
- generic [ref=e166]: "*"
|
||||||
|
- textbox "Customer Email Address *" [invalid] [ref=e168]: instanda-smoke-20260703@example.com
|
||||||
|
- generic [ref=e169]: The email address entered is invalid.
|
||||||
|
- button "Submit" [ref=e171] [cursor=pointer]
|
||||||
|
- paragraph
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=e92]:
|
||||||
|
- complementary [ref=e97]:
|
||||||
|
- list [ref=e99]:
|
||||||
|
- listitem [ref=e100]:
|
||||||
|
- link "Home" [ref=e101] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- listitem [ref=e102]:
|
||||||
|
- link "Blog" [ref=e103] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/blog
|
||||||
|
- listitem [ref=e104]:
|
||||||
|
- link "Contact" [ref=e105] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- contentinfo "Site" [ref=e108]:
|
||||||
|
- generic [ref=e110]:
|
||||||
|
- text: © 2026 HUB Insurance • Built with
|
||||||
|
- link "GeneratePress" [ref=e111] [cursor=pointer]:
|
||||||
|
- /url: https://generatepress.com
|
||||||
|
- text:
|
||||||
|
- generic [ref=e172]: "There was a problem with your submission, Please review the fields below, Customer Email Address: The email address entered is invalid,"
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
- generic [ref=e1]:
|
||||||
|
- link "Skip to content" [ref=e2] [cursor=pointer]:
|
||||||
|
- /url: "#content"
|
||||||
|
- banner "Site" [ref=e3]:
|
||||||
|
- generic [ref=e4]:
|
||||||
|
- link "HUB Insurance" [ref=e6] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- img "HUB Insurance" [ref=e7]
|
||||||
|
- navigation "Primary" [ref=e8]:
|
||||||
|
- list [ref=e11]:
|
||||||
|
- listitem [ref=e12]:
|
||||||
|
- link "About" [ref=e13] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/about
|
||||||
|
- listitem [ref=e14]:
|
||||||
|
- link "Contact" [ref=e15] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- listitem [ref=e16]:
|
||||||
|
- link "Get a Quote" [ref=e17] [cursor=pointer]:
|
||||||
|
- /url: "#get-a-quote"
|
||||||
|
- generic [ref=e19]:
|
||||||
|
- heading "Special Event Insurance" [level=1] [ref=e20]:
|
||||||
|
- text: Special
|
||||||
|
- emphasis [ref=e21]: Event
|
||||||
|
- text: Insurance
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=e22]: "{Hero Content} Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||||
|
- list [ref=e23]:
|
||||||
|
- listitem [ref=e24]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e25]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e26]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=e27]: Lorem ipsum dolor
|
||||||
|
- paragraph
|
||||||
|
- link "Hero CTA Lorem" [ref=e28] [cursor=pointer]:
|
||||||
|
- /url: https://www.getfused.com
|
||||||
|
- main [ref=e32]:
|
||||||
|
- generic [ref=e33]:
|
||||||
|
- generic [ref=e34]:
|
||||||
|
- generic [ref=e35]:
|
||||||
|
- paragraph [ref=e36]: How it Works
|
||||||
|
- heading "Three Simple Steps" [level=2] [ref=e37]
|
||||||
|
- generic [ref=e38]:
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=e39]:
|
||||||
|
- generic [ref=e115]:
|
||||||
|
- text: There was a problem with your submission. Please review the fields below.
|
||||||
|
- list [ref=e116]:
|
||||||
|
- listitem [ref=e117]:
|
||||||
|
- 'link "Customer Email Address: The email address entered is invalid." [ref=e118] [cursor=pointer]':
|
||||||
|
- /url: "#field_5_10"
|
||||||
|
- generic [ref=e119]:
|
||||||
|
- heading "Start a Quote" [level=2] [ref=e120]
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=e121]: An asterisk (*) indicates a required field.
|
||||||
|
- generic [ref=e122]:
|
||||||
|
- generic [ref=e124]:
|
||||||
|
- generic [ref=e125]:
|
||||||
|
- generic [ref=e126]:
|
||||||
|
- text: Event Role
|
||||||
|
- generic [ref=e128]: "*"
|
||||||
|
- combobox "Event Role *" [ref=e130]:
|
||||||
|
- option
|
||||||
|
- option "Event Host or Organizer" [selected]
|
||||||
|
- option "Vendor, Exhibitor or Subcontractor"
|
||||||
|
- option "Performer, Entertainer or DJ"
|
||||||
|
- generic [ref=e131]:
|
||||||
|
- generic [ref=e132]:
|
||||||
|
- text: Activity / Event Type
|
||||||
|
- generic [ref=e134]: "*"
|
||||||
|
- combobox "Activity / Event Type *" [ref=e136]:
|
||||||
|
- option
|
||||||
|
- option "Animal Adoption Event"
|
||||||
|
- option "Animal Shows"
|
||||||
|
- option "Antique Show"
|
||||||
|
- option "Art Festival"
|
||||||
|
- option "Art Show"
|
||||||
|
- option "Auction"
|
||||||
|
- option "Award Presentation"
|
||||||
|
- option "Baby Shower"
|
||||||
|
- option "Bachelor Party"
|
||||||
|
- option "Bachelorette Party"
|
||||||
|
- option "Badminton Tournament / Event"
|
||||||
|
- option "Bake Sale"
|
||||||
|
- option "Ballet"
|
||||||
|
- option "Banquet"
|
||||||
|
- option "Baptism"
|
||||||
|
- option "Bar/Bat Mitzvah"
|
||||||
|
- option "Bar/Pub Crawl"
|
||||||
|
- option "Baseball Tournament / Event"
|
||||||
|
- option "Basketball Tournament / Event"
|
||||||
|
- option "Battle of the Bands"
|
||||||
|
- option "Bazaar"
|
||||||
|
- option "Beauty Pageant"
|
||||||
|
- option "Beer Garden/Tent"
|
||||||
|
- option "Beer Mile"
|
||||||
|
- option "Billiards Tournament / Event"
|
||||||
|
- option "Bingo Games"
|
||||||
|
- option "Birthday Party" [selected]
|
||||||
|
- option "Block Parties/Street Closures/Street Fairs"
|
||||||
|
- option "BMX Tournament / Event"
|
||||||
|
- option "Boat Show (On Land)"
|
||||||
|
- option "Boat Show"
|
||||||
|
- option "Bocce Ball"
|
||||||
|
- option "Body Building Tournament / Event"
|
||||||
|
- option "Book Fair"
|
||||||
|
- option "Book Signing"
|
||||||
|
- option "Bowling Tournament / Event"
|
||||||
|
- option "Boxing Tournament / Event"
|
||||||
|
- option "Breakfast"
|
||||||
|
- option "Bridal Shower"
|
||||||
|
- option "Brunch - No Admission Charge - Invite Only"
|
||||||
|
- option "Business Meeting"
|
||||||
|
- option "Business Party"
|
||||||
|
- option "Cage Fight Tournament / Event"
|
||||||
|
- option "Cannabis Event"
|
||||||
|
- option "Car Show"
|
||||||
|
- option "Car Wash"
|
||||||
|
- option "Card Games"
|
||||||
|
- option "Casino Night"
|
||||||
|
- option "Cheerleading Tournament / Event"
|
||||||
|
- option "Chess Tournament"
|
||||||
|
- option "Church Service or Meeting"
|
||||||
|
- option "Cocktail Party - No Admission Charge - Invite Only"
|
||||||
|
- option "College Reunion"
|
||||||
|
- option "Comedy Show"
|
||||||
|
- option "Company Retreats"
|
||||||
|
- option "Concert - Choir"
|
||||||
|
- option "Concert - Classic Rock"
|
||||||
|
- option "Concert - Classical"
|
||||||
|
- option "Concert - Country"
|
||||||
|
- option "Concert - Doo-Wop"
|
||||||
|
- option "Concert - Electronic/EDM"
|
||||||
|
- option "Concert - Folk Guitar"
|
||||||
|
- option "Concert - Foreign"
|
||||||
|
- option "Concert - Heavy Metal"
|
||||||
|
- option "Concert - High Profile Performer"
|
||||||
|
- option "Concert - Hip Hop/Rap"
|
||||||
|
- option "Concert - Jazz"
|
||||||
|
- option "Concert - Music Festivals"
|
||||||
|
- option "Concert - Opera"
|
||||||
|
- option "Concert - Orchestra"
|
||||||
|
- option "Concert - Pop"
|
||||||
|
- option "Concert - R&B"
|
||||||
|
- option "Concert - Reggae"
|
||||||
|
- option "Concert - Rock"
|
||||||
|
- option "Concert - SKA"
|
||||||
|
- option "Concert - Soul"
|
||||||
|
- option "Concert - Symphony"
|
||||||
|
- option "Concert - Tribute Bands"
|
||||||
|
- option "Consumer Show"
|
||||||
|
- option "Cooking Competition"
|
||||||
|
- option "Corn Mazes"
|
||||||
|
- option "Cornhole Tournament / Event"
|
||||||
|
- option "Costume Contest"
|
||||||
|
- option "Craft Show"
|
||||||
|
- option "Cycling"
|
||||||
|
- option "Dance Competition"
|
||||||
|
- option "Dance Recital"
|
||||||
|
- option "Dance Team Tournament / Event"
|
||||||
|
- option "Debutante Ball"
|
||||||
|
- option "Demolition Derby"
|
||||||
|
- option "Dinner - No Admission Charge - Invite Only"
|
||||||
|
- option "Dirt Bike Tournament / Event"
|
||||||
|
- option "Dog Show"
|
||||||
|
- option "Drive-In Movie/Concert"
|
||||||
|
- option "Egg Hunt"
|
||||||
|
- option "Engagement Party"
|
||||||
|
- option "Exotic Dancer Event"
|
||||||
|
- option "Extreme Sporting Tournament / Event"
|
||||||
|
- option "Family Reunion"
|
||||||
|
- option "Farm Show"
|
||||||
|
- option "Farmer's Market"
|
||||||
|
- option "Fashion Show"
|
||||||
|
- option "Fencing Tournament / Event"
|
||||||
|
- option "Field Hockey Tournament / Event"
|
||||||
|
- option "Film Screenings"
|
||||||
|
- option "Film Shoot (In Studio)"
|
||||||
|
- option "First Communion"
|
||||||
|
- option "Fishing Tournament/Event"
|
||||||
|
- option "Flag Football Tournament / Event"
|
||||||
|
- option "Flea Market"
|
||||||
|
- option "Flower Show"
|
||||||
|
- option "Food Festival"
|
||||||
|
- option "Football Tournament / Event"
|
||||||
|
- option "Fraternity/Sorority Party"
|
||||||
|
- option "Frisbee Golf Tournament / Event"
|
||||||
|
- option "Fundraiser Dinner"
|
||||||
|
- option "Funeral Service"
|
||||||
|
- option "Gala with Seated Dinner"
|
||||||
|
- option "Garden Show"
|
||||||
|
- option "Gift Wrapping Party"
|
||||||
|
- option "Golf Tournament / Event"
|
||||||
|
- option "Gymnastics Tournament / Event"
|
||||||
|
- option "Haunted Houses"
|
||||||
|
- option "Health Fair"
|
||||||
|
- option "High School Graduation Party"
|
||||||
|
- option "High School Reunion"
|
||||||
|
- option "High School Graduation Ceremony"
|
||||||
|
- option "Holiday Character (Santa, Easter Bunny, etc.)"
|
||||||
|
- option "Holiday Party – No Admission Charge – Invite Only"
|
||||||
|
- option "Home and Garden Tour"
|
||||||
|
- option "Horse Show/Competition"
|
||||||
|
- option "Ice Hockey Tournament / Event"
|
||||||
|
- option "Ice Skating Show / Event"
|
||||||
|
- option "Indoor Convention"
|
||||||
|
- option "Indoor Tradeshow"
|
||||||
|
- option "Jewelry Show"
|
||||||
|
- option "Job Fair"
|
||||||
|
- option "Lacrosse Tournament / Event"
|
||||||
|
- option "Lecture"
|
||||||
|
- option "Livestock Auction"
|
||||||
|
- option "Luncheon"
|
||||||
|
- option "Magic Show"
|
||||||
|
- option "Marching Band Tournament / Event"
|
||||||
|
- option "Mardis Gras Party"
|
||||||
|
- option "Martial Arts Tournament / Event"
|
||||||
|
- option "Math Tournament"
|
||||||
|
- option "Medical Conference"
|
||||||
|
- option "Meeting"
|
||||||
|
- option "Memorial Service"
|
||||||
|
- option "Mixed Martial Arts Tournament / Event"
|
||||||
|
- option "Motocross"
|
||||||
|
- option "Motorcycle or Race Car On Road Competition"
|
||||||
|
- option "Motorcycle Run"
|
||||||
|
- option "Mud Bogs"
|
||||||
|
- option "New Year's Eve Party"
|
||||||
|
- option "Parade with Floats"
|
||||||
|
- option "Parade without Floats"
|
||||||
|
- option "Piano Recital"
|
||||||
|
- option "Pickleball Tournament / Event"
|
||||||
|
- option "Picnics"
|
||||||
|
- option "Pig Roast"
|
||||||
|
- option "Play Readings"
|
||||||
|
- option "Poetry Reading"
|
||||||
|
- option "Poker Runs"
|
||||||
|
- option "Political Rally"
|
||||||
|
- option "Prom"
|
||||||
|
- option "Quinceanera"
|
||||||
|
- option "Renaissance Fairs"
|
||||||
|
- option "Retirement Party"
|
||||||
|
- option "Road Race (13.2M or longer)"
|
||||||
|
- option "Road Race (Running only; 13.1M or less)"
|
||||||
|
- option "Rummage Sale"
|
||||||
|
- option "Seminar"
|
||||||
|
- option "Skateboarding Tournament / Event"
|
||||||
|
- option "Soccer Tournament / Event"
|
||||||
|
- option "Softball Tournament / Event"
|
||||||
|
- option "Spikeball Tournament / Event"
|
||||||
|
- option "Surfing Tournament / Event"
|
||||||
|
- option "Swimming Tournament / Event"
|
||||||
|
- option "Tap Dancing Show"
|
||||||
|
- option "Tennis Tournament / Event"
|
||||||
|
- option "Theatrical Production"
|
||||||
|
- option "Toy Drive"
|
||||||
|
- option "Track and Field Tournament / Event"
|
||||||
|
- option "Triathlon Tournament / Event"
|
||||||
|
- option "Trivia Night"
|
||||||
|
- option "Ultimate Frisbee Tournament / Event"
|
||||||
|
- option "Valentine's Day Party"
|
||||||
|
- option "Video Games Contests"
|
||||||
|
- option "Volleyball Tournament / Event"
|
||||||
|
- option "Voter Registration"
|
||||||
|
- option "Walk-a-thon Tournament / Event"
|
||||||
|
- option "Wedding Anniversary Party"
|
||||||
|
- option "Wedding Ceremony and/or Reception"
|
||||||
|
- option "Weightlifting Tournament / Event"
|
||||||
|
- option "Wrestling Tournament / Event"
|
||||||
|
- option "Yard Sale"
|
||||||
|
- option "Yoga Tournament / Event"
|
||||||
|
- option "Zumba Tournament / Event"
|
||||||
|
- generic [ref=e137]:
|
||||||
|
- generic [ref=e138]:
|
||||||
|
- text: Event Location
|
||||||
|
- generic [ref=e140]: "*"
|
||||||
|
- combobox "Event Location *" [ref=e142]:
|
||||||
|
- option
|
||||||
|
- option "Alabama"
|
||||||
|
- option "Alaska"
|
||||||
|
- option "Arizona"
|
||||||
|
- option "Arkansas"
|
||||||
|
- option "California"
|
||||||
|
- option "Colorado"
|
||||||
|
- option "Connecticut"
|
||||||
|
- option "Delaware"
|
||||||
|
- option "District of Columbia"
|
||||||
|
- option "Florida"
|
||||||
|
- option "Georgia"
|
||||||
|
- option "Hawaii"
|
||||||
|
- option "Idaho"
|
||||||
|
- option "Illinois"
|
||||||
|
- option "Indiana"
|
||||||
|
- option "Iowa"
|
||||||
|
- option "Kansas"
|
||||||
|
- option "Kentucky"
|
||||||
|
- option "Louisiana"
|
||||||
|
- option "Maine"
|
||||||
|
- option "Maryland"
|
||||||
|
- option "Massachusetts"
|
||||||
|
- option "Michigan"
|
||||||
|
- option "Minnesota"
|
||||||
|
- option "Mississippi"
|
||||||
|
- option "Missouri"
|
||||||
|
- option "Montana"
|
||||||
|
- option "Nebraska"
|
||||||
|
- option "Nevada"
|
||||||
|
- option "New Hampshire"
|
||||||
|
- option "New Jersey"
|
||||||
|
- option "New Mexico"
|
||||||
|
- option "New York" [selected]
|
||||||
|
- option "North Carolina"
|
||||||
|
- option "North Dakota"
|
||||||
|
- option "Ohio"
|
||||||
|
- option "Oklahoma"
|
||||||
|
- option "Oregon"
|
||||||
|
- option "Pennsylvania"
|
||||||
|
- option "Rhode Island"
|
||||||
|
- option "South Carolina"
|
||||||
|
- option "South Dakota"
|
||||||
|
- option "Tennessee"
|
||||||
|
- option "Texas"
|
||||||
|
- option "Utah"
|
||||||
|
- option "Vermont"
|
||||||
|
- option "Virginia"
|
||||||
|
- option "Washington"
|
||||||
|
- option "West Virginia"
|
||||||
|
- option "Wisconsin"
|
||||||
|
- option "Wyoming"
|
||||||
|
- generic [ref=e143]:
|
||||||
|
- generic [ref=e144]:
|
||||||
|
- text: Maximum Daily Attendance
|
||||||
|
- generic [ref=e146]: "*"
|
||||||
|
- spinbutton "Maximum Daily Attendance *" [ref=e148]: "100"
|
||||||
|
- generic [ref=e149]:
|
||||||
|
- generic [ref=e150]:
|
||||||
|
- text: Event Start Date
|
||||||
|
- generic [ref=e152]: "*"
|
||||||
|
- generic [ref=e153]:
|
||||||
|
- textbox "Event Start Date *" [ref=e154]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- text: 2026-09-01
|
||||||
|
- generic [ref=e155]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=e156]:
|
||||||
|
- generic [ref=e157]:
|
||||||
|
- text: Event End Date
|
||||||
|
- generic [ref=e159]: "*"
|
||||||
|
- generic [ref=e160]:
|
||||||
|
- textbox "Event End Date *" [ref=e161]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- text: 2026-09-03
|
||||||
|
- generic [ref=e162]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=e163]:
|
||||||
|
- generic [ref=e164]:
|
||||||
|
- text: Customer Email Address
|
||||||
|
- generic [ref=e166]: "*"
|
||||||
|
- textbox "Customer Email Address *" [invalid] [ref=e168]: instanda-smoke@getfused.com
|
||||||
|
- generic [ref=e169]: The email address entered is invalid.
|
||||||
|
- button "Submit" [active] [ref=e171] [cursor=pointer]
|
||||||
|
- paragraph
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=e92]:
|
||||||
|
- complementary [ref=e97]:
|
||||||
|
- list [ref=e99]:
|
||||||
|
- listitem [ref=e100]:
|
||||||
|
- link "Home" [ref=e101] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- listitem [ref=e102]:
|
||||||
|
- link "Blog" [ref=e103] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/blog
|
||||||
|
- listitem [ref=e104]:
|
||||||
|
- link "Contact" [ref=e105] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- contentinfo "Site" [ref=e108]:
|
||||||
|
- generic [ref=e110]:
|
||||||
|
- text: © 2026 HUB Insurance • Built with
|
||||||
|
- link "GeneratePress" [ref=e111] [cursor=pointer]:
|
||||||
|
- /url: https://generatepress.com
|
||||||
|
- text:
|
||||||
|
- generic [ref=e172]: "There was a problem with your submission, Please review the fields below, Customer Email Address: The email address entered is invalid,"
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
- generic [active] [ref=f2e1]:
|
||||||
|
- generic [ref=f2e2]:
|
||||||
|
- banner [ref=f2e4]:
|
||||||
|
- navigation [ref=f2e5]:
|
||||||
|
- generic [ref=f2e6]:
|
||||||
|
- link "consumer.instanda.us" [ref=f2e8] [cursor=pointer]:
|
||||||
|
- /url: /Public/Index
|
||||||
|
- img "consumer.instanda.us" [ref=f2e9]
|
||||||
|
- list [ref=f2e11]:
|
||||||
|
- listitem [ref=f2e12]:
|
||||||
|
- link "Home" [ref=f2e13] [cursor=pointer]:
|
||||||
|
- /url: /Public/Index
|
||||||
|
- listitem [ref=f2e14]:
|
||||||
|
- link "Get a quote for HUB Special Event Insurance" [ref=f2e15] [cursor=pointer]:
|
||||||
|
- /url: /Public/PreQuoteQuestions?PackageId=25536&pageNumber=1
|
||||||
|
- listitem [ref=f2e16]:
|
||||||
|
- link "Retrieve quote" [ref=f2e17] [cursor=pointer]:
|
||||||
|
- /url: /Public/RetrieveQuote
|
||||||
|
- form [ref=f2e23]:
|
||||||
|
- generic [ref=f2e24]:
|
||||||
|
- generic [ref=f2e25]: Password
|
||||||
|
- textbox [ref=f2e26]
|
||||||
|
- button "Sign In" [ref=f2e28] [cursor=pointer]
|
||||||
|
- contentinfo [ref=f2e29]:
|
||||||
|
- generic [ref=f2e30]:
|
||||||
|
- text: Site built and hosted using
|
||||||
|
- link "Instanda" [ref=f2e31] [cursor=pointer]:
|
||||||
|
- /url: http://www.instanda.com/
|
||||||
|
- text: v1.107.0.6 insurance software.
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
- generic [active] [ref=f3e1]:
|
||||||
|
- link "Skip to content" [ref=f3e2] [cursor=pointer]:
|
||||||
|
- /url: "#content"
|
||||||
|
- banner "Site" [ref=f3e3]:
|
||||||
|
- generic [ref=f3e4]:
|
||||||
|
- link "HUB Insurance" [ref=f3e6] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- img "HUB Insurance" [ref=f3e7]
|
||||||
|
- navigation "Primary" [ref=f3e8]:
|
||||||
|
- list [ref=f3e11]:
|
||||||
|
- listitem [ref=f3e12]:
|
||||||
|
- link "About" [ref=f3e13] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/about
|
||||||
|
- listitem [ref=f3e14]:
|
||||||
|
- link "Contact" [ref=f3e15] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- listitem [ref=f3e16]:
|
||||||
|
- link "Get a Quote" [ref=f3e17] [cursor=pointer]:
|
||||||
|
- /url: "#get-a-quote"
|
||||||
|
- generic [ref=f3e19]:
|
||||||
|
- heading "Special Event Insurance" [level=1] [ref=f3e20]:
|
||||||
|
- text: Special
|
||||||
|
- emphasis [ref=f3e21]: Event
|
||||||
|
- text: Insurance
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=f3e22]: "{Hero Content} Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||||
|
- list [ref=f3e23]:
|
||||||
|
- listitem [ref=f3e24]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=f3e25]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=f3e26]: Lorem ipsum dolor
|
||||||
|
- listitem [ref=f3e27]: Lorem ipsum dolor
|
||||||
|
- paragraph
|
||||||
|
- link "Hero CTA Lorem" [ref=f3e28] [cursor=pointer]:
|
||||||
|
- /url: https://www.getfused.com
|
||||||
|
- main [ref=f3e32]:
|
||||||
|
- generic [ref=f3e33]:
|
||||||
|
- generic [ref=f3e34]:
|
||||||
|
- generic [ref=f3e35]:
|
||||||
|
- paragraph [ref=f3e36]: How it Works
|
||||||
|
- heading "Three Simple Steps" [level=2] [ref=f3e37]
|
||||||
|
- generic [ref=f3e38]:
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=f3e39]:
|
||||||
|
- generic [ref=f3e40]:
|
||||||
|
- heading "Start a Quote" [level=2] [ref=f3e41]
|
||||||
|
- paragraph
|
||||||
|
- paragraph [ref=f3e42]: An asterisk (*) indicates a required field.
|
||||||
|
- generic [ref=f3e43]:
|
||||||
|
- generic [ref=f3e45]:
|
||||||
|
- generic [ref=f3e46]:
|
||||||
|
- generic [ref=f3e47]:
|
||||||
|
- text: Event Role
|
||||||
|
- generic [ref=f3e49]: "*"
|
||||||
|
- combobox "Event Role *" [ref=f3e51]:
|
||||||
|
- option [selected]
|
||||||
|
- option "Event Host or Organizer"
|
||||||
|
- option "Vendor, Exhibitor or Subcontractor"
|
||||||
|
- option "Performer, Entertainer or DJ"
|
||||||
|
- generic [ref=f3e52]:
|
||||||
|
- generic [ref=f3e53]:
|
||||||
|
- text: Activity / Event Type
|
||||||
|
- generic [ref=f3e55]: "*"
|
||||||
|
- combobox "Activity / Event Type *" [ref=f3e57]:
|
||||||
|
- option [selected]
|
||||||
|
- option "Animal Adoption Event"
|
||||||
|
- option "Animal Shows"
|
||||||
|
- option "Antique Show"
|
||||||
|
- option "Art Festival"
|
||||||
|
- option "Art Show"
|
||||||
|
- option "Auction"
|
||||||
|
- option "Award Presentation"
|
||||||
|
- option "Baby Shower"
|
||||||
|
- option "Bachelor Party"
|
||||||
|
- option "Bachelorette Party"
|
||||||
|
- option "Badminton Tournament / Event"
|
||||||
|
- option "Bake Sale"
|
||||||
|
- option "Ballet"
|
||||||
|
- option "Banquet"
|
||||||
|
- option "Baptism"
|
||||||
|
- option "Bar/Bat Mitzvah"
|
||||||
|
- option "Bar/Pub Crawl"
|
||||||
|
- option "Baseball Tournament / Event"
|
||||||
|
- option "Basketball Tournament / Event"
|
||||||
|
- option "Battle of the Bands"
|
||||||
|
- option "Bazaar"
|
||||||
|
- option "Beauty Pageant"
|
||||||
|
- option "Beer Garden/Tent"
|
||||||
|
- option "Beer Mile"
|
||||||
|
- option "Billiards Tournament / Event"
|
||||||
|
- option "Bingo Games"
|
||||||
|
- option "Birthday Party"
|
||||||
|
- option "Block Parties/Street Closures/Street Fairs"
|
||||||
|
- option "BMX Tournament / Event"
|
||||||
|
- option "Boat Show (On Land)"
|
||||||
|
- option "Boat Show"
|
||||||
|
- option "Bocce Ball"
|
||||||
|
- option "Body Building Tournament / Event"
|
||||||
|
- option "Book Fair"
|
||||||
|
- option "Book Signing"
|
||||||
|
- option "Bowling Tournament / Event"
|
||||||
|
- option "Boxing Tournament / Event"
|
||||||
|
- option "Breakfast"
|
||||||
|
- option "Bridal Shower"
|
||||||
|
- option "Brunch - No Admission Charge - Invite Only"
|
||||||
|
- option "Business Meeting"
|
||||||
|
- option "Business Party"
|
||||||
|
- option "Cage Fight Tournament / Event"
|
||||||
|
- option "Cannabis Event"
|
||||||
|
- option "Car Show"
|
||||||
|
- option "Car Wash"
|
||||||
|
- option "Card Games"
|
||||||
|
- option "Casino Night"
|
||||||
|
- option "Cheerleading Tournament / Event"
|
||||||
|
- option "Chess Tournament"
|
||||||
|
- option "Church Service or Meeting"
|
||||||
|
- option "Cocktail Party - No Admission Charge - Invite Only"
|
||||||
|
- option "College Reunion"
|
||||||
|
- option "Comedy Show"
|
||||||
|
- option "Company Retreats"
|
||||||
|
- option "Concert - Choir"
|
||||||
|
- option "Concert - Classic Rock"
|
||||||
|
- option "Concert - Classical"
|
||||||
|
- option "Concert - Country"
|
||||||
|
- option "Concert - Doo-Wop"
|
||||||
|
- option "Concert - Electronic/EDM"
|
||||||
|
- option "Concert - Folk Guitar"
|
||||||
|
- option "Concert - Foreign"
|
||||||
|
- option "Concert - Heavy Metal"
|
||||||
|
- option "Concert - High Profile Performer"
|
||||||
|
- option "Concert - Hip Hop/Rap"
|
||||||
|
- option "Concert - Jazz"
|
||||||
|
- option "Concert - Music Festivals"
|
||||||
|
- option "Concert - Opera"
|
||||||
|
- option "Concert - Orchestra"
|
||||||
|
- option "Concert - Pop"
|
||||||
|
- option "Concert - R&B"
|
||||||
|
- option "Concert - Reggae"
|
||||||
|
- option "Concert - Rock"
|
||||||
|
- option "Concert - SKA"
|
||||||
|
- option "Concert - Soul"
|
||||||
|
- option "Concert - Symphony"
|
||||||
|
- option "Concert - Tribute Bands"
|
||||||
|
- option "Consumer Show"
|
||||||
|
- option "Cooking Competition"
|
||||||
|
- option "Corn Mazes"
|
||||||
|
- option "Cornhole Tournament / Event"
|
||||||
|
- option "Costume Contest"
|
||||||
|
- option "Craft Show"
|
||||||
|
- option "Cycling"
|
||||||
|
- option "Dance Competition"
|
||||||
|
- option "Dance Recital"
|
||||||
|
- option "Dance Team Tournament / Event"
|
||||||
|
- option "Debutante Ball"
|
||||||
|
- option "Demolition Derby"
|
||||||
|
- option "Dinner - No Admission Charge - Invite Only"
|
||||||
|
- option "Dirt Bike Tournament / Event"
|
||||||
|
- option "Dog Show"
|
||||||
|
- option "Drive-In Movie/Concert"
|
||||||
|
- option "Egg Hunt"
|
||||||
|
- option "Engagement Party"
|
||||||
|
- option "Exotic Dancer Event"
|
||||||
|
- option "Extreme Sporting Tournament / Event"
|
||||||
|
- option "Family Reunion"
|
||||||
|
- option "Farm Show"
|
||||||
|
- option "Farmer's Market"
|
||||||
|
- option "Fashion Show"
|
||||||
|
- option "Fencing Tournament / Event"
|
||||||
|
- option "Field Hockey Tournament / Event"
|
||||||
|
- option "Film Screenings"
|
||||||
|
- option "Film Shoot (In Studio)"
|
||||||
|
- option "First Communion"
|
||||||
|
- option "Fishing Tournament/Event"
|
||||||
|
- option "Flag Football Tournament / Event"
|
||||||
|
- option "Flea Market"
|
||||||
|
- option "Flower Show"
|
||||||
|
- option "Food Festival"
|
||||||
|
- option "Football Tournament / Event"
|
||||||
|
- option "Fraternity/Sorority Party"
|
||||||
|
- option "Frisbee Golf Tournament / Event"
|
||||||
|
- option "Fundraiser Dinner"
|
||||||
|
- option "Funeral Service"
|
||||||
|
- option "Gala with Seated Dinner"
|
||||||
|
- option "Garden Show"
|
||||||
|
- option "Gift Wrapping Party"
|
||||||
|
- option "Golf Tournament / Event"
|
||||||
|
- option "Gymnastics Tournament / Event"
|
||||||
|
- option "Haunted Houses"
|
||||||
|
- option "Health Fair"
|
||||||
|
- option "High School Graduation Party"
|
||||||
|
- option "High School Reunion"
|
||||||
|
- option "High School Graduation Ceremony"
|
||||||
|
- option "Holiday Character (Santa, Easter Bunny, etc.)"
|
||||||
|
- option "Holiday Party – No Admission Charge – Invite Only"
|
||||||
|
- option "Home and Garden Tour"
|
||||||
|
- option "Horse Show/Competition"
|
||||||
|
- option "Ice Hockey Tournament / Event"
|
||||||
|
- option "Ice Skating Show / Event"
|
||||||
|
- option "Indoor Convention"
|
||||||
|
- option "Indoor Tradeshow"
|
||||||
|
- option "Jewelry Show"
|
||||||
|
- option "Job Fair"
|
||||||
|
- option "Lacrosse Tournament / Event"
|
||||||
|
- option "Lecture"
|
||||||
|
- option "Livestock Auction"
|
||||||
|
- option "Luncheon"
|
||||||
|
- option "Magic Show"
|
||||||
|
- option "Marching Band Tournament / Event"
|
||||||
|
- option "Mardis Gras Party"
|
||||||
|
- option "Martial Arts Tournament / Event"
|
||||||
|
- option "Math Tournament"
|
||||||
|
- option "Medical Conference"
|
||||||
|
- option "Meeting"
|
||||||
|
- option "Memorial Service"
|
||||||
|
- option "Mixed Martial Arts Tournament / Event"
|
||||||
|
- option "Motocross"
|
||||||
|
- option "Motorcycle or Race Car On Road Competition"
|
||||||
|
- option "Motorcycle Run"
|
||||||
|
- option "Mud Bogs"
|
||||||
|
- option "New Year's Eve Party"
|
||||||
|
- option "Parade with Floats"
|
||||||
|
- option "Parade without Floats"
|
||||||
|
- option "Piano Recital"
|
||||||
|
- option "Pickleball Tournament / Event"
|
||||||
|
- option "Picnics"
|
||||||
|
- option "Pig Roast"
|
||||||
|
- option "Play Readings"
|
||||||
|
- option "Poetry Reading"
|
||||||
|
- option "Poker Runs"
|
||||||
|
- option "Political Rally"
|
||||||
|
- option "Prom"
|
||||||
|
- option "Quinceanera"
|
||||||
|
- option "Renaissance Fairs"
|
||||||
|
- option "Retirement Party"
|
||||||
|
- option "Road Race (13.2M or longer)"
|
||||||
|
- option "Road Race (Running only; 13.1M or less)"
|
||||||
|
- option "Rummage Sale"
|
||||||
|
- option "Seminar"
|
||||||
|
- option "Skateboarding Tournament / Event"
|
||||||
|
- option "Soccer Tournament / Event"
|
||||||
|
- option "Softball Tournament / Event"
|
||||||
|
- option "Spikeball Tournament / Event"
|
||||||
|
- option "Surfing Tournament / Event"
|
||||||
|
- option "Swimming Tournament / Event"
|
||||||
|
- option "Tap Dancing Show"
|
||||||
|
- option "Tennis Tournament / Event"
|
||||||
|
- option "Theatrical Production"
|
||||||
|
- option "Toy Drive"
|
||||||
|
- option "Track and Field Tournament / Event"
|
||||||
|
- option "Triathlon Tournament / Event"
|
||||||
|
- option "Trivia Night"
|
||||||
|
- option "Ultimate Frisbee Tournament / Event"
|
||||||
|
- option "Valentine's Day Party"
|
||||||
|
- option "Video Games Contests"
|
||||||
|
- option "Volleyball Tournament / Event"
|
||||||
|
- option "Voter Registration"
|
||||||
|
- option "Walk-a-thon Tournament / Event"
|
||||||
|
- option "Wedding Anniversary Party"
|
||||||
|
- option "Wedding Ceremony and/or Reception"
|
||||||
|
- option "Weightlifting Tournament / Event"
|
||||||
|
- option "Wrestling Tournament / Event"
|
||||||
|
- option "Yard Sale"
|
||||||
|
- option "Yoga Tournament / Event"
|
||||||
|
- option "Zumba Tournament / Event"
|
||||||
|
- generic [ref=f3e58]:
|
||||||
|
- generic [ref=f3e59]:
|
||||||
|
- text: Event Location
|
||||||
|
- generic [ref=f3e61]: "*"
|
||||||
|
- combobox "Event Location *" [ref=f3e63]:
|
||||||
|
- option [selected]
|
||||||
|
- option "Alabama"
|
||||||
|
- option "Alaska"
|
||||||
|
- option "Arizona"
|
||||||
|
- option "Arkansas"
|
||||||
|
- option "California"
|
||||||
|
- option "Colorado"
|
||||||
|
- option "Connecticut"
|
||||||
|
- option "Delaware"
|
||||||
|
- option "District of Columbia"
|
||||||
|
- option "Florida"
|
||||||
|
- option "Georgia"
|
||||||
|
- option "Hawaii"
|
||||||
|
- option "Idaho"
|
||||||
|
- option "Illinois"
|
||||||
|
- option "Indiana"
|
||||||
|
- option "Iowa"
|
||||||
|
- option "Kansas"
|
||||||
|
- option "Kentucky"
|
||||||
|
- option "Louisiana"
|
||||||
|
- option "Maine"
|
||||||
|
- option "Maryland"
|
||||||
|
- option "Massachusetts"
|
||||||
|
- option "Michigan"
|
||||||
|
- option "Minnesota"
|
||||||
|
- option "Mississippi"
|
||||||
|
- option "Missouri"
|
||||||
|
- option "Montana"
|
||||||
|
- option "Nebraska"
|
||||||
|
- option "Nevada"
|
||||||
|
- option "New Hampshire"
|
||||||
|
- option "New Jersey"
|
||||||
|
- option "New Mexico"
|
||||||
|
- option "New York"
|
||||||
|
- option "North Carolina"
|
||||||
|
- option "North Dakota"
|
||||||
|
- option "Ohio"
|
||||||
|
- option "Oklahoma"
|
||||||
|
- option "Oregon"
|
||||||
|
- option "Pennsylvania"
|
||||||
|
- option "Rhode Island"
|
||||||
|
- option "South Carolina"
|
||||||
|
- option "South Dakota"
|
||||||
|
- option "Tennessee"
|
||||||
|
- option "Texas"
|
||||||
|
- option "Utah"
|
||||||
|
- option "Vermont"
|
||||||
|
- option "Virginia"
|
||||||
|
- option "Washington"
|
||||||
|
- option "West Virginia"
|
||||||
|
- option "Wisconsin"
|
||||||
|
- option "Wyoming"
|
||||||
|
- generic [ref=f3e64]:
|
||||||
|
- generic [ref=f3e65]:
|
||||||
|
- text: Maximum Daily Attendance
|
||||||
|
- generic [ref=f3e67]: "*"
|
||||||
|
- spinbutton "Maximum Daily Attendance *" [ref=f3e69]
|
||||||
|
- generic [ref=f3e70]:
|
||||||
|
- generic [ref=f3e71]:
|
||||||
|
- text: Event Start Date
|
||||||
|
- generic [ref=f3e73]: "*"
|
||||||
|
- generic [ref=f3e74]:
|
||||||
|
- textbox "Event Start Date *" [ref=f3e75]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- generic [ref=f3e76]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=f3e77]:
|
||||||
|
- generic [ref=f3e78]:
|
||||||
|
- text: Event End Date
|
||||||
|
- generic [ref=f3e80]: "*"
|
||||||
|
- generic [ref=f3e81]:
|
||||||
|
- textbox "Event End Date *" [ref=f3e82]:
|
||||||
|
- /placeholder: yyyy-mm-dd
|
||||||
|
- generic [ref=f3e83]: YYYY dash MM dash DD
|
||||||
|
- generic [ref=f3e84]:
|
||||||
|
- generic [ref=f3e85]:
|
||||||
|
- text: Customer Email Address
|
||||||
|
- generic [ref=f3e87]: "*"
|
||||||
|
- textbox "Customer Email Address *" [ref=f3e89]
|
||||||
|
- button "Submit" [ref=f3e91] [cursor=pointer]
|
||||||
|
- paragraph
|
||||||
|
- paragraph
|
||||||
|
- generic [ref=f3e92]:
|
||||||
|
- complementary [ref=f3e97]:
|
||||||
|
- list [ref=f3e99]:
|
||||||
|
- listitem [ref=f3e100]:
|
||||||
|
- link "Home" [ref=f3e101] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/
|
||||||
|
- listitem [ref=f3e102]:
|
||||||
|
- link "Blog" [ref=f3e103] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/blog
|
||||||
|
- listitem [ref=f3e104]:
|
||||||
|
- link "Contact" [ref=f3e105] [cursor=pointer]:
|
||||||
|
- /url: https://hubinsurance.mystagingwebsite.com/contact
|
||||||
|
- contentinfo "Site" [ref=f3e108]:
|
||||||
|
- generic [ref=f3e110]:
|
||||||
|
- text: © 2026 HUB Insurance • Built with
|
||||||
|
- link "GeneratePress" [ref=f3e111] [cursor=pointer]:
|
||||||
|
- /url: https://generatepress.com
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/cache
|
||||||
|
/project.local.yml
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
# the name by which the project can be referenced within Serena
|
||||||
|
project_name: "hub-insurance"
|
||||||
|
|
||||||
|
|
||||||
|
# list of languages for which language servers are started; choose from:
|
||||||
|
# al angular ansible bash clojure
|
||||||
|
# cpp cpp_ccls crystal csharp csharp_omnisharp
|
||||||
|
# dart elixir elm erlang fortran
|
||||||
|
# fsharp go groovy haskell haxe
|
||||||
|
# hlsl html java json julia
|
||||||
|
# kotlin lean4 lua luau markdown
|
||||||
|
# matlab msl nix ocaml pascal
|
||||||
|
# perl php php_phpactor powershell python
|
||||||
|
# python_jedi python_ty r rego ruby
|
||||||
|
# ruby_solargraph rust scala scss solidity
|
||||||
|
# svelte swift systemverilog terraform toml
|
||||||
|
# typescript typescript_vts vue yaml zig
|
||||||
|
# (This list may be outdated. For the current list, see values of Language enum here:
|
||||||
|
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
|
||||||
|
# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
|
||||||
|
# Note:
|
||||||
|
# - For C, use cpp
|
||||||
|
# - For JavaScript, use typescript
|
||||||
|
# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root)
|
||||||
|
# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm)
|
||||||
|
# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three)
|
||||||
|
# - For Free Pascal/Lazarus, use pascal
|
||||||
|
# Special requirements:
|
||||||
|
# Some languages require additional setup/installations.
|
||||||
|
# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
|
||||||
|
# When using multiple languages, the first language server that supports a given file will be used for that file.
|
||||||
|
# The first language is the default language and the respective language server will be used as a fallback.
|
||||||
|
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
|
||||||
|
languages:
|
||||||
|
- php
|
||||||
|
|
||||||
|
# the encoding used by text files in the project
|
||||||
|
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
|
||||||
|
encoding: "utf-8"
|
||||||
|
|
||||||
|
# line ending convention to use when writing source files.
|
||||||
|
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
|
||||||
|
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
|
||||||
|
line_ending:
|
||||||
|
|
||||||
|
# The language backend to use for this project.
|
||||||
|
# If not set, the global setting from serena_config.yml is used.
|
||||||
|
# Valid values: LSP, JetBrains
|
||||||
|
# Note: the backend is fixed at startup. If a project with a different backend
|
||||||
|
# is activated post-init, an error will be returned.
|
||||||
|
language_backend:
|
||||||
|
|
||||||
|
# whether to use project's .gitignore files to ignore files
|
||||||
|
ignore_all_files_in_gitignore: true
|
||||||
|
|
||||||
|
# advanced configuration option allowing to configure language server-specific options.
|
||||||
|
# Maps the language key to the options.
|
||||||
|
# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available.
|
||||||
|
# No documentation on options means no options are available.
|
||||||
|
ls_specific_settings: {}
|
||||||
|
|
||||||
|
# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos).
|
||||||
|
# Paths can be absolute or relative to the project root.
|
||||||
|
# Each folder is registered as an LSP workspace folder, enabling language servers to discover
|
||||||
|
# symbols and references across package boundaries.
|
||||||
|
# Currently supported for: TypeScript.
|
||||||
|
# Example:
|
||||||
|
# additional_workspace_folders:
|
||||||
|
# - ../sibling-package
|
||||||
|
# - ../shared-lib
|
||||||
|
additional_workspace_folders: []
|
||||||
|
|
||||||
|
# list of additional paths to ignore in this project.
|
||||||
|
# Same syntax as gitignore, so you can use * and **.
|
||||||
|
# Note: global ignored_paths from serena_config.yml are also applied additively.
|
||||||
|
ignored_paths: []
|
||||||
|
|
||||||
|
# whether the project is in read-only mode
|
||||||
|
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
|
||||||
|
# Added on 2025-04-18
|
||||||
|
read_only: false
|
||||||
|
|
||||||
|
# list of tool names to exclude.
|
||||||
|
# This extends the existing exclusions (e.g. from the global configuration)
|
||||||
|
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
|
||||||
|
excluded_tools: []
|
||||||
|
|
||||||
|
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default).
|
||||||
|
# This extends the existing inclusions (e.g. from the global configuration).
|
||||||
|
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
|
||||||
|
included_optional_tools: []
|
||||||
|
|
||||||
|
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
|
||||||
|
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
|
||||||
|
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
|
||||||
|
fixed_tools: []
|
||||||
|
|
||||||
|
# list of mode names that are to be activated by default, overriding the setting in the global configuration.
|
||||||
|
# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes.
|
||||||
|
# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply.
|
||||||
|
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
|
||||||
|
# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply
|
||||||
|
# for this project.
|
||||||
|
# This setting can, in turn, be overridden by CLI parameters (--mode).
|
||||||
|
# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes
|
||||||
|
default_modes:
|
||||||
|
|
||||||
|
# list of mode names to be activated additionally for this project, e.g. ["query-projects"]
|
||||||
|
# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes.
|
||||||
|
# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes
|
||||||
|
added_modes:
|
||||||
|
|
||||||
|
# initial prompt for the project. It will always be given to the LLM upon activating the project
|
||||||
|
# (contrary to the memories, which are loaded on demand).
|
||||||
|
initial_prompt: ""
|
||||||
|
|
||||||
|
# time budget (seconds) per tool call for the retrieval of additional symbol information
|
||||||
|
# such as docstrings or parameter information.
|
||||||
|
# This overrides the corresponding setting in the global configuration; see the documentation there.
|
||||||
|
# If null or missing, use the setting from the global configuration.
|
||||||
|
symbol_info_budget:
|
||||||
|
|
||||||
|
# list of regex patterns which, when matched, mark a memory entry as read‑only.
|
||||||
|
# Extends the list from the global configuration, merging the two lists.
|
||||||
|
read_only_memory_patterns: []
|
||||||
|
|
||||||
|
# list of regex patterns for memories to completely ignore.
|
||||||
|
# Matching memories will not appear in list_memories or activate_project output
|
||||||
|
# and cannot be accessed via read_memory or write_memory.
|
||||||
|
# To access ignored memory files, use the read_file tool on the raw file path.
|
||||||
|
# Extends the list from the global configuration, merging the two lists.
|
||||||
|
# Example: ["_archive/.*", "_episodes/.*"]
|
||||||
|
ignored_memory_patterns: []
|
||||||
Binary file not shown.
@@ -3,7 +3,7 @@
|
|||||||
* Plugin Name: ESP INSTANDA Start Quote Integration
|
* Plugin Name: ESP INSTANDA Start Quote Integration
|
||||||
* Plugin URI: https://getfused.com
|
* Plugin URI: https://getfused.com
|
||||||
* Description: Pushes Gravity Forms "Start a Quote" submissions into INSTANDA's Package API with write-ahead transaction logging, native entry recording, admin resubmit, and a test-mode lock. Form-agnostic - attach the feed to any form.
|
* Description: Pushes Gravity Forms "Start a Quote" submissions into INSTANDA's Package API with write-ahead transaction logging, native entry recording, admin resubmit, and a test-mode lock. Form-agnostic - attach the feed to any form.
|
||||||
* Version: 1.0.7
|
* Version: 1.1.0
|
||||||
* Requires at least: 7.0
|
* Requires at least: 7.0
|
||||||
* Requires PHP: 8.5
|
* Requires PHP: 8.5
|
||||||
* Author: Getfused
|
* Author: Getfused
|
||||||
@@ -75,25 +75,36 @@ function platform_blockers(): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
\add_action('admin_init', static function (): void {
|
\add_action('admin_init', static function (): void {
|
||||||
|
if (!empty(platform_blockers())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Keep the schema current if the plugin was updated without re-activation.
|
// Keep the schema current if the plugin was updated without re-activation.
|
||||||
if (empty(platform_blockers()) && Transaction_Store::needs_migration()) {
|
if (Transaction_Store::needs_migration()) {
|
||||||
Transaction_Store::install_table();
|
Transaction_Store::install_table();
|
||||||
}
|
}
|
||||||
|
// Self-heal the retention cron if its scheduled event was ever lost (the schema
|
||||||
|
// self-heals above; the cron must too, or retention silently stops forever).
|
||||||
|
if (!\wp_next_scheduled(CLEANUP_HOOK)) {
|
||||||
|
\wp_schedule_event(time(), 'daily', CLEANUP_HOOK);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Requirements notice registered UNCONDITIONALLY: gform_loaded never fires when Gravity
|
||||||
|
// Forms is absent, so a notice registered only inside it would be unreachable in exactly
|
||||||
|
// the case (GF missing) an admin most needs to see it.
|
||||||
|
\add_action('admin_notices', static function (): void {
|
||||||
|
$errors = platform_blockers();
|
||||||
|
if ($errors) {
|
||||||
|
echo '<div class="notice notice-error"><p><strong>ESP INSTANDA Integration is inactive:</strong> '
|
||||||
|
. esc_html(implode(' ', $errors)) . '</p></div>';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* ------------------------------------------------ Gravity Forms Add-On registration */
|
/* ------------------------------------------------ Gravity Forms Add-On registration */
|
||||||
|
|
||||||
\add_action('gform_loaded', Guard::wrap(static function (): void {
|
\add_action('gform_loaded', Guard::wrap(static function (): void {
|
||||||
if (!empty(platform_blockers()) || !method_exists('GFForms', 'include_feed_addon_framework')) {
|
if (!empty(platform_blockers()) || !method_exists('GFForms', 'include_feed_addon_framework')) {
|
||||||
\add_action('admin_notices', static function (): void {
|
return; // the requirements notice is registered unconditionally above
|
||||||
$errors = platform_blockers();
|
|
||||||
if (!$errors) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
echo '<div class="notice notice-error"><p><strong>ESP INSTANDA Integration is inactive:</strong> '
|
|
||||||
. esc_html(implode(' ', $errors)) . '</p></div>';
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\GFForms::include_feed_addon_framework();
|
\GFForms::include_feed_addon_framework();
|
||||||
@@ -111,7 +122,7 @@ function platform_blockers(): array {
|
|||||||
require_once __DIR__ . '/includes/class-instanda-addon.php';
|
require_once __DIR__ . '/includes/class-instanda-addon.php';
|
||||||
|
|
||||||
\GFAddOn::register(Instanda_AddOn::class);
|
\GFAddOn::register(Instanda_AddOn::class);
|
||||||
}, 5));
|
}), 5);
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- cron cleanup */
|
/* ----------------------------------------------------------------- cron cleanup */
|
||||||
|
|
||||||
|
|||||||
@@ -158,7 +158,9 @@ final class Api_Client {
|
|||||||
$data = is_array($data) ? $data : [];
|
$data = is_array($data) ? $data : [];
|
||||||
|
|
||||||
if ($code >= 200 && $code < 300) {
|
if ($code >= 200 && $code < 300) {
|
||||||
$ref = isset($data['quoteRef']) ? (string) $data['quoteRef'] : null;
|
// An empty-string quoteRef is not usable - treat it as missing so the caller
|
||||||
|
// handles the 2xx-without-quoteRef case as ambiguous, not as a delivered quote.
|
||||||
|
$ref = isset($data['quoteRef']) && $data['quoteRef'] !== '' ? (string) $data['quoteRef'] : null;
|
||||||
$url = isset($data['urlSingleUse']) ? (string) $data['urlSingleUse'] : null;
|
$url = isset($data['urlSingleUse']) ? (string) $data['urlSingleUse'] : null;
|
||||||
return Api_Result::success($code, $ref, $url, $excerpt);
|
return Api_Result::success($code, $ref, $url, $excerpt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,11 @@
|
|||||||
* an explicit, gated switch to Live - see the Go-Live checklist.
|
* an explicit, gated switch to Live - see the Go-Live checklist.
|
||||||
*
|
*
|
||||||
* Secrets entered in the admin UI are encrypted at rest with libsodium
|
* Secrets entered in the admin UI are encrypted at rest with libsodium
|
||||||
* (sodium_crypto_secretbox, XSalsa20-Poly1305). The key comes from the
|
* (sodium_crypto_secretbox, XSalsa20-Poly1305). The "a database dump alone never
|
||||||
* SPG_INSTANDA_KEY constant, so a database dump alone never exposes a usable secret.
|
* exposes a usable secret" guarantee holds ONLY when the SPG_INSTANDA_KEY constant is
|
||||||
|
* set: without it the key is self-provisioned into the DB (see db_key()), so the key
|
||||||
|
* and ciphertext live in the same database and a dump recovers the password. Set
|
||||||
|
* SPG_INSTANDA_KEY (and the credential constants) in production for the hardened posture.
|
||||||
* Live credentials are expected as constants and are never written to the database.
|
* Live credentials are expected as constants and are never written to the database.
|
||||||
*
|
*
|
||||||
* @package ESP\Instanda
|
* @package ESP\Instanda
|
||||||
|
|||||||
@@ -28,5 +28,12 @@ final class Cron_Cleanup {
|
|||||||
if ($deleted > 0) {
|
if ($deleted > 0) {
|
||||||
Logger::debug("Retention purge removed {$deleted} delivered transaction(s) older than {$days} day(s).");
|
Logger::debug("Retention purge removed {$deleted} delivered transaction(s) older than {$days} day(s).");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scrub PII from unresolved (failed/pending) rows past the window; they are never
|
||||||
|
// timer-deleted, so this bounds how long customer PII is retained on them.
|
||||||
|
$scrubbed = $store->anonymize_stale_unresolved($days);
|
||||||
|
if ($scrubbed > 0) {
|
||||||
|
Logger::debug("Retention scrub anonymized PII on {$scrubbed} unresolved transaction(s) older than {$days} day(s).");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,37 @@ final class Field_Mapper {
|
|||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanity-check a stored StartQuote wire body before re-sending it (resubmit trust
|
||||||
|
* boundary): the DB is treated as untrusted input. Returns error codes (empty = ok).
|
||||||
|
* Pure - uses a fixed UTC zone since only Y-m-d well-formedness is being checked.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $body A body previously built by to_payload().
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function validate_payload(array $body): array {
|
||||||
|
$errors = [];
|
||||||
|
foreach (['Role', 'ActivityType', 'PQ_LocationState_CHOICE'] as $key) {
|
||||||
|
if (trim((string) ($body[$key] ?? '')) === '') {
|
||||||
|
$errors[] = $key . '_missing';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$this->is_positive_integer($body['PQ_MaximumDailyAttendance_NUM'] ?? null)) {
|
||||||
|
$errors[] = 'attendance_invalid';
|
||||||
|
}
|
||||||
|
$email = trim((string) ($body['PQ_CustomerEmailAddress_TXT'] ?? ''));
|
||||||
|
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$errors[] = 'email_invalid';
|
||||||
|
}
|
||||||
|
$tz = new \DateTimeZone('UTC');
|
||||||
|
foreach (['PQ_EventStart_DATE', 'PQ_EventEnd_DATE'] as $key) {
|
||||||
|
if ($this->parse_date((string) ($body[$key] ?? ''), $tz) === null) {
|
||||||
|
$errors[] = $key . '_invalid';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
/** D8 - inclusive consecutive-day count: (end - start) + 1; a single-day event is 1. */
|
/** D8 - inclusive consecutive-day count: (end - start) + 1; a single-day event is 1. */
|
||||||
private function consecutive_days(\DateTimeImmutable $start, \DateTimeImmutable $end): int {
|
private function consecutive_days(\DateTimeImmutable $start, \DateTimeImmutable $end): int {
|
||||||
return (int) $start->diff($end)->days + 1;
|
return (int) $start->diff($end)->days + 1;
|
||||||
|
|||||||
@@ -106,9 +106,29 @@ final class Go_Live {
|
|||||||
['key' => 'A2', 'label' => 'Alert email recipient(s)', 'detail' => $emails !== '' ? $emails : 'None set', 'pass' => $emails !== ''],
|
['key' => 'A2', 'label' => 'Alert email recipient(s)', 'detail' => $emails !== '' ? $emails : 'None set', 'pass' => $emails !== ''],
|
||||||
['key' => 'A3', 'label' => 'Front-end form submit + redirect verified in a browser', 'detail' => $this->ack_detail('espinstanda_frontend_ack'), 'pass' => (bool) get_option('espinstanda_frontend_ack')],
|
['key' => 'A3', 'label' => 'Front-end form submit + redirect verified in a browser', 'detail' => $this->ack_detail('espinstanda_frontend_ack'), 'pass' => (bool) get_option('espinstanda_frontend_ack')],
|
||||||
['key' => 'A4', 'label' => 'No unresolved failures', 'detail' => $unresolved === 0 ? 'Clean' : "{$unresolved} unresolved", 'pass' => $unresolved === 0],
|
['key' => 'A4', 'label' => 'No unresolved failures', 'detail' => $unresolved === 0 ? 'Clean' : "{$unresolved} unresolved", 'pass' => $unresolved === 0],
|
||||||
|
['key' => 'A5', 'label' => 'Exactly one active INSTANDA feed', 'detail' => $this->feed_summary(), 'pass' => $this->active_feed_count() === 1],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Count active INSTANDA feeds across all forms (should be exactly one at go-live). */
|
||||||
|
private function active_feed_count(): int {
|
||||||
|
if (!class_exists(__NAMESPACE__ . '\\Instanda_AddOn')) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$feeds = Instanda_AddOn::get_instance()->get_feeds();
|
||||||
|
return count(array_filter((array) $feeds, static fn ($f) => !empty($f['is_active'])));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function feed_summary(): string {
|
||||||
|
$n = $this->active_feed_count();
|
||||||
|
if ($n === 1) {
|
||||||
|
return '1 active feed';
|
||||||
|
}
|
||||||
|
return $n === 0
|
||||||
|
? 'No active feed - the quote form will not push to INSTANDA'
|
||||||
|
: "{$n} active feeds - deactivate all but the canonical quote form (a stray test-form feed also creates quotes)";
|
||||||
|
}
|
||||||
|
|
||||||
/** @return array{complete:int,total:int,ready:bool} */
|
/** @return array{complete:int,total:int,ready:bool} */
|
||||||
public function readiness(): array {
|
public function readiness(): array {
|
||||||
$blocking = $this->blocking_items();
|
$blocking = $this->blocking_items();
|
||||||
@@ -129,6 +149,10 @@ final class Go_Live {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
update_option('espinstanda_operating_mode', 'live');
|
update_option('espinstanda_operating_mode', 'live');
|
||||||
|
// Switching the mode must also select the Live environment, mirroring
|
||||||
|
// return_to_test(); otherwise environment() stays clamped to Test and real
|
||||||
|
// customer quotes would keep hitting the Test endpoint after go-live.
|
||||||
|
update_option('espinstanda_env', 'live');
|
||||||
update_option('espinstanda_operating_mode_audit', [
|
update_option('espinstanda_operating_mode_audit', [
|
||||||
'actor' => get_current_user_id(),
|
'actor' => get_current_user_id(),
|
||||||
'ts' => current_time('mysql'),
|
'ts' => current_time('mysql'),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace ESP\Instanda;
|
|||||||
|
|
||||||
final class Instanda_AddOn extends \GFFeedAddOn {
|
final class Instanda_AddOn extends \GFFeedAddOn {
|
||||||
|
|
||||||
protected $_version = '1.0.7';
|
protected $_version = '1.1.0';
|
||||||
protected $_min_gravityforms_version = '2.10.3';
|
protected $_min_gravityforms_version = '2.10.3';
|
||||||
protected $_slug = 'espinstanda';
|
protected $_slug = 'espinstanda';
|
||||||
protected $_path = 'esp-instanda-integration/esp-instanda-integration.php';
|
protected $_path = 'esp-instanda-integration/esp-instanda-integration.php';
|
||||||
@@ -71,6 +71,9 @@ final class Instanda_AddOn extends \GFFeedAddOn {
|
|||||||
|
|
||||||
add_action('esp_instanda_resubmit', Guard::wrap([Resubmit_Handler::class, 'run']));
|
add_action('esp_instanda_resubmit', Guard::wrap([Resubmit_Handler::class, 'run']));
|
||||||
|
|
||||||
|
// Data-subject erasure: wire customer transactions into WP's Erase Personal Data tool.
|
||||||
|
add_filter('wp_privacy_personal_data_erasers', Guard::wrap([$this, 'register_privacy_erasers']));
|
||||||
|
|
||||||
// Keep Gravity Forms' scripts out of Jetpack Boost's JS concat/defer, which
|
// Keep Gravity Forms' scripts out of Jetpack Boost's JS concat/defer, which
|
||||||
// otherwise break GF's AJAX init and the post-submit INSTANDA redirect.
|
// otherwise break GF's AJAX init and the post-submit INSTANDA redirect.
|
||||||
Boost_Compat::register();
|
Boost_Compat::register();
|
||||||
@@ -389,7 +392,14 @@ JS;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($tx === null || $tx->quote_ref === null) {
|
if ($tx === null || $tx->quote_ref === null) {
|
||||||
return; // nothing delivered to record (defensive)
|
// No-silent-failure: an async feed with no resolvable delivered transaction means
|
||||||
|
// entry meta / note / notification are being skipped - make that visible.
|
||||||
|
Logger::error(sprintf(
|
||||||
|
'record_feed_result: no delivered transaction for entry #%d (dedupe %s); entry meta/notification not recorded.',
|
||||||
|
$entry_id,
|
||||||
|
(string) (Submission::current_dedupe() ?? 'n/a')
|
||||||
|
));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry_Integration::record($entry_id, $tx->quote_ref, (string) $tx->quote_url, 'delivered', $tx->environment);
|
Entry_Integration::record($entry_id, $tx->quote_ref, (string) $tx->quote_url, 'delivered', $tx->environment);
|
||||||
@@ -402,6 +412,27 @@ JS;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ privacy */
|
||||||
|
|
||||||
|
public function register_privacy_erasers($erasers) {
|
||||||
|
$erasers['esp-instanda'] = [
|
||||||
|
'eraser_friendly_name' => 'INSTANDA quote transactions',
|
||||||
|
'callback' => [$this, 'privacy_erase'],
|
||||||
|
];
|
||||||
|
return $erasers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** WP Erase Personal Data callback - deletes all INSTANDA transactions for an email. */
|
||||||
|
public function privacy_erase($email, $page = 1) {
|
||||||
|
$removed = (new Transaction_Store())->delete_by_email((string) $email);
|
||||||
|
return [
|
||||||
|
'items_removed' => $removed > 0,
|
||||||
|
'items_retained' => false,
|
||||||
|
'messages' => [],
|
||||||
|
'done' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ admin pages */
|
/* ------------------------------------------------------------ admin pages */
|
||||||
|
|
||||||
public function register_admin_pages() {
|
public function register_admin_pages() {
|
||||||
@@ -463,7 +494,8 @@ JS;
|
|||||||
|
|
||||||
echo '<h2>Event log</h2><ul class="espinstanda-timeline">';
|
echo '<h2>Event log</h2><ul class="espinstanda-timeline">';
|
||||||
foreach ($tx->event_log as $e) {
|
foreach ($tx->event_log as $e) {
|
||||||
echo '<li><code>' . esc_html($e['ts'] ?? '') . '</code> ' . esc_html($e['message'] ?? '') . '</li>';
|
$ts = isset($e['ts']) && $e['ts'] !== '' ? get_date_from_gmt((string) $e['ts'], 'Y-m-d H:i') : '';
|
||||||
|
echo '<li><code>' . esc_html($ts) . '</code> ' . esc_html($e['message'] ?? '') . '</li>';
|
||||||
}
|
}
|
||||||
echo '</ul>';
|
echo '</ul>';
|
||||||
|
|
||||||
@@ -475,7 +507,8 @@ JS;
|
|||||||
'Status' => ucfirst($tx->status), 'Environment' => strtoupper($tx->environment),
|
'Status' => ucfirst($tx->status), 'Environment' => strtoupper($tx->environment),
|
||||||
'quoteRef' => $tx->quote_ref ?? '—', 'HTTP' => $tx->http_status ?? '—',
|
'quoteRef' => $tx->quote_ref ?? '—', 'HTTP' => $tx->http_status ?? '—',
|
||||||
'Retries' => $tx->retry_count, 'Dedupe key' => $tx->dedupe_key,
|
'Retries' => $tx->retry_count, 'Dedupe key' => $tx->dedupe_key,
|
||||||
'Customer' => $tx->customer_email, 'Created' => $tx->created_at,
|
'Customer' => $tx->customer_email,
|
||||||
|
'Created' => $tx->created_at !== '' ? get_date_from_gmt($tx->created_at, 'Y-m-d H:i') : '—',
|
||||||
];
|
];
|
||||||
foreach ($rows as $k => $v) {
|
foreach ($rows as $k => $v) {
|
||||||
echo '<tr><th>' . esc_html($k) . '</th><td>' . esc_html((string) $v) . '</td></tr>';
|
echo '<tr><th>' . esc_html($k) . '</th><td>' . esc_html((string) $v) . '</td></tr>';
|
||||||
@@ -592,6 +625,9 @@ JS;
|
|||||||
if ($tx === null) {
|
if ($tx === null) {
|
||||||
wp_send_json_error(['message' => 'Not found']);
|
wp_send_json_error(['message' => 'Not found']);
|
||||||
}
|
}
|
||||||
|
if ($tx->status === Tx_Status::Delivered->value) {
|
||||||
|
wp_send_json_error(['message' => 'Already delivered - resubmitting would create a duplicate quote']);
|
||||||
|
}
|
||||||
if ($tx->environment !== Config::environment()->value) {
|
if ($tx->environment !== Config::environment()->value) {
|
||||||
wp_send_json_error(['message' => 'Cross-environment resubmit is blocked']);
|
wp_send_json_error(['message' => 'Cross-environment resubmit is blocked']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ final class Submission {
|
|||||||
private const LOCK_TTL = 60; // seconds
|
private const LOCK_TTL = 60; // seconds
|
||||||
private const RESULT_TTL = 120;
|
private const RESULT_TTL = 120;
|
||||||
private const STASH_TTL = 300;
|
private const STASH_TTL = 300;
|
||||||
|
public const DEDUPE_WINDOW = 1800; // 30 min - collapse identical resubmits to the existing quote
|
||||||
|
private const RL_IP_MAX = 20; // valid submissions per IP per hour
|
||||||
|
private const RL_EMAIL_MAX = 5; // valid submissions per email per hour
|
||||||
|
private const RL_WINDOW = 3600; // rate-limit window (seconds)
|
||||||
|
|
||||||
/** Wire var key => feed meta key (the mapped GF field id is stored under each). */
|
/** Wire var key => feed meta key (the mapped GF field id is stored under each). */
|
||||||
private const FIELD_KEYS = [
|
private const FIELD_KEYS = [
|
||||||
@@ -55,22 +59,44 @@ final class Submission {
|
|||||||
return $validation_result; // GATE 3 - only act on the final page
|
return $validation_result; // GATE 3 - only act on the final page
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $this->submission_token($form);
|
// Fail CLOSED for this one submission if the create path throws (no quote-less
|
||||||
|
// entry saved), keep the form working for everyone else, and surface the failure.
|
||||||
|
try {
|
||||||
|
return $this->process($validation_result, $form, $feed);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Guard::report($e);
|
||||||
|
$this->record_hard_failure($e);
|
||||||
|
$this->pending_message = 'We could not start your quote just now. Please try again.';
|
||||||
|
return $this->mark_form_invalid($validation_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The gated INSTANDA create - runs only after GATE 1-3 pass, inside validate()'s guard. */
|
||||||
|
private function process(array $validation_result, array $form, array $feed): array {
|
||||||
|
$token = $this->submission_token($form);
|
||||||
if (!$this->acquire_lock($token)) {
|
if (!$this->acquire_lock($token)) {
|
||||||
return $this->replay($token, $validation_result); // GATE 4 - duplicate fire: replay cached outcome
|
return $this->replay($token, $validation_result); // GATE 4 - within-request double-fire
|
||||||
}
|
}
|
||||||
|
|
||||||
$dedupe = $this->dedupe_key($token);
|
|
||||||
$store = new Transaction_Store();
|
$store = new Transaction_Store();
|
||||||
|
$values = $this->extract_values($form, $feed);
|
||||||
|
$dedupe = $this->content_dedupe_key($form, $values); // content-addressed, stable across requests
|
||||||
|
|
||||||
// Own double-fire guard: a prior attempt for this submission already delivered.
|
// Cross-request duplicate guard: an identical submission already delivered
|
||||||
$existing = $store->find_by_dedupe($dedupe);
|
// recently -> reuse its quote instead of creating a second one at INSTANDA.
|
||||||
if ($existing !== null && $existing->status === Tx_Status::Delivered->value) {
|
$existing = $store->recent_delivered_by_dedupe($dedupe, self::DEDUPE_WINDOW);
|
||||||
|
if ($existing !== null) {
|
||||||
$this->stash_success($dedupe, (string) $existing->quote_ref, $existing->quote_url);
|
$this->stash_success($dedupe, (string) $existing->quote_ref, $existing->quote_url);
|
||||||
return $this->remember($token, $validation_result, true);
|
return $this->remember($token, $validation_result, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$values = $this->extract_values($form, $feed);
|
// Race guard: serialize concurrent identical submits (atomic where a persistent
|
||||||
|
// object cache is present, e.g. production; degrades to a transient lock locally).
|
||||||
|
if (!$this->acquire_content_lock($dedupe)) {
|
||||||
|
$this->pending_message = 'We are finalizing your quote - please wait a moment and try again.';
|
||||||
|
return $this->remember($token, $this->mark_form_invalid($validation_result), false);
|
||||||
|
}
|
||||||
|
|
||||||
$mapper = new Field_Mapper();
|
$mapper = new Field_Mapper();
|
||||||
$tz = wp_timezone_string();
|
$tz = wp_timezone_string();
|
||||||
|
|
||||||
@@ -80,6 +106,13 @@ final class Submission {
|
|||||||
return $this->remember($token, $validation_result, false);
|
return $this->remember($token, $validation_result, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Abuse control: throttle the paid API + PII table per IP and per email.
|
||||||
|
$throttle = $this->rate_limit_message((string) ($values['customer_email'] ?? ''));
|
||||||
|
if ($throttle !== null) {
|
||||||
|
$this->pending_message = $throttle;
|
||||||
|
return $this->remember($token, $this->mark_form_invalid($validation_result), false);
|
||||||
|
}
|
||||||
|
|
||||||
$body = $mapper->to_payload($values, $tz);
|
$body = $mapper->to_payload($values, $tz);
|
||||||
|
|
||||||
// Write-ahead: persist BEFORE the HTTP call (redacted body carries no secrets).
|
// Write-ahead: persist BEFORE the HTTP call (redacted body carries no secrets).
|
||||||
@@ -94,35 +127,47 @@ final class Submission {
|
|||||||
$tx->role_label = (string) ($values['role'] ?? '');
|
$tx->role_label = (string) ($values['role'] ?? '');
|
||||||
$tx->redacted_payload = (string) wp_json_encode($body);
|
$tx->redacted_payload = (string) wp_json_encode($body);
|
||||||
$tx_id = $store->create_pending($tx);
|
$tx_id = $store->create_pending($tx);
|
||||||
|
|
||||||
|
// A failed write-ahead insert means we cannot audit the call - do not send it.
|
||||||
|
if ($tx_id === 0) {
|
||||||
|
Logger::error('Write-ahead insert failed; aborting StartQuote to avoid an unaudited call.');
|
||||||
|
$this->alert_failure($this->synth_tx($form, $values, $dedupe, 'Write-ahead insert failed - submission not sent.'), null);
|
||||||
|
Failure_Surface::bump();
|
||||||
|
$this->pending_message = $this->friendly_failure_message(true);
|
||||||
|
return $this->remember($token, $this->mark_form_invalid($validation_result), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = (new Api_Client())->start_quote($body, $dedupe);
|
$result = (new Api_Client())->start_quote($body, $dedupe);
|
||||||
|
$has_ref = $result->quote_ref !== null && $result->quote_ref !== '';
|
||||||
|
|
||||||
if ($result->ok && $result->quote_ref !== null) {
|
if ($result->ok && $has_ref) {
|
||||||
if ($tx_id) {
|
if ($tx_id) {
|
||||||
$store->mark_success($tx_id, $result->quote_ref, $result->url_single_use, $result->http_status);
|
$store->mark_success($tx_id, (string) $result->quote_ref, $result->url_single_use, $result->http_status);
|
||||||
}
|
}
|
||||||
$this->stash_success($dedupe, $result->quote_ref, $result->url_single_use);
|
$this->stash_success($dedupe, (string) $result->quote_ref, $result->url_single_use);
|
||||||
return $this->remember($token, $validation_result, true);
|
return $this->remember($token, $validation_result, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failure / ambiguous timeout - input preserved, no entry saved.
|
// Failure / ambiguous - input preserved, no entry saved. A 2xx without a usable
|
||||||
|
// quoteRef is ambiguous too: INSTANDA may have created a quote we cannot see.
|
||||||
|
$ambiguous = $result->is_ambiguous || ($result->ok && !$has_ref);
|
||||||
if ($tx_id) {
|
if ($tx_id) {
|
||||||
if ($result->is_ambiguous) {
|
if ($ambiguous) {
|
||||||
$store->mark_ambiguous($tx_id, $result->http_status, $result->error_string());
|
$store->mark_ambiguous($tx_id, $result->http_status, $result->error_string());
|
||||||
} else {
|
} else {
|
||||||
$store->mark_failed($tx_id, $result->http_status, $result->response_excerpt, $result->error_string());
|
$store->mark_failed($tx_id, $result->http_status, $result->response_excerpt, $result->error_string());
|
||||||
}
|
}
|
||||||
$stored = $store->find($tx_id);
|
$stored = $store->find($tx_id) ?? $this->synth_tx($form, $values, $dedupe, $result->error_string());
|
||||||
if ($stored !== null) {
|
} else {
|
||||||
(new Notifier())->validation_failure_alert($stored, $result);
|
// Storage disabled - still surface the failure (no silent drop).
|
||||||
}
|
$stored = $this->synth_tx($form, $values, $dedupe, $result->error_string());
|
||||||
}
|
}
|
||||||
|
$this->alert_failure($stored, $result);
|
||||||
Failure_Surface::bump();
|
Failure_Surface::bump();
|
||||||
|
|
||||||
$this->pending_message = $this->friendly_failure_message($result);
|
$this->pending_message = $this->friendly_failure_message($ambiguous);
|
||||||
$invalid = $this->mark_form_invalid($validation_result);
|
return $this->remember($token, $this->mark_form_invalid($validation_result), false);
|
||||||
return $this->remember($token, $invalid, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** gform_validation_message filter - surface our form-level failure message. */
|
/** gform_validation_message filter - surface our form-level failure message. */
|
||||||
@@ -164,10 +209,10 @@ final class Submission {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function read_stash_for_entry(array $form): array {
|
private function read_stash_for_entry(array $form): array {
|
||||||
// Best-effort: the confirmation runs in the same request as a fresh success.
|
// Best-effort: confirmation runs in the same request as a fresh success, so the
|
||||||
$token = $this->submission_token($form);
|
// content dedupe key was recorded in the request-scoped static during validate().
|
||||||
$dedupe = $this->dedupe_key($token);
|
$dedupe = self::$current_dedupe;
|
||||||
return $this->read_stash($dedupe) ?? [];
|
return $dedupe !== null ? ($this->read_stash($dedupe) ?? []) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------- feed + values */
|
/* ----------------------------------------------------------- feed + values */
|
||||||
@@ -228,12 +273,31 @@ final class Submission {
|
|||||||
return 'espinstanda_' . $unique;
|
return 'espinstanda_' . $unique;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function dedupe_key(string $token): string {
|
/**
|
||||||
return substr('dk_' . md5($token), 0, 64);
|
* Content-addressed dedupe key: two submissions of the same form with the same
|
||||||
|
* mapped field values produce the same key, so an identical re-POST or a
|
||||||
|
* retry-after-error collapses to the existing quote instead of creating a new one.
|
||||||
|
*/
|
||||||
|
private function content_dedupe_key(array $form, array $values): string {
|
||||||
|
$parts = [(string) ($form['id'] ?? '')];
|
||||||
|
foreach (self::FIELD_KEYS as $key) {
|
||||||
|
$v = trim((string) ($values[$key] ?? ''));
|
||||||
|
$parts[] = $key === 'customer_email' ? strtolower($v) : $v;
|
||||||
|
}
|
||||||
|
return 'dk_' . substr(hash('sha256', implode('|', $parts)), 0, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Per-request lock: stops a single submission from double-firing within one request. */
|
||||||
private function acquire_lock(string $token): bool {
|
private function acquire_lock(string $token): bool {
|
||||||
$key = 'lock_' . md5($token);
|
return $this->try_lock('lock_' . md5($token));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Brief atomic lock on the content key: serializes concurrent identical submits. */
|
||||||
|
private function acquire_content_lock(string $dedupe): bool {
|
||||||
|
return $this->try_lock('clock_' . md5($dedupe));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function try_lock(string $key): bool {
|
||||||
if (function_exists('wp_cache_add') && wp_cache_add($key, 1, 'espinstanda', self::LOCK_TTL)) {
|
if (function_exists('wp_cache_add') && wp_cache_add($key, 1, 'espinstanda', self::LOCK_TTL)) {
|
||||||
set_transient('espinstanda_' . $key, 1, self::LOCK_TTL);
|
set_transient('espinstanda_' . $key, 1, self::LOCK_TTL);
|
||||||
return true;
|
return true;
|
||||||
@@ -307,10 +371,62 @@ final class Submission {
|
|||||||
unset($field);
|
unset($field);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function friendly_failure_message(Api_Result $result): string {
|
private function friendly_failure_message(bool $ambiguous): string {
|
||||||
if ($result->is_ambiguous) {
|
if ($ambiguous) {
|
||||||
return 'We could not confirm your quote. Please try again in a moment - we have saved your details.';
|
return 'We could not confirm your quote. Please try again in a moment - we have saved your details.';
|
||||||
}
|
}
|
||||||
return 'We could not start your quote just now. Please review your entries and try again.';
|
return 'We could not start your quote just now. Please review your entries and try again.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------- abuse control */
|
||||||
|
|
||||||
|
/** A friendly message when over the per-IP or per-email hourly limit, else null. */
|
||||||
|
private function rate_limit_message(string $email): ?string {
|
||||||
|
$ip = isset($_SERVER['REMOTE_ADDR']) ? (string) $_SERVER['REMOTE_ADDR'] : '';
|
||||||
|
if ($ip !== '' && $this->bump_counter('rl_ip_' . md5($ip)) > self::RL_IP_MAX) {
|
||||||
|
return 'Too many quote attempts from your connection. Please try again later.';
|
||||||
|
}
|
||||||
|
$email = strtolower(trim($email));
|
||||||
|
if ($email !== '' && $this->bump_counter('rl_email_' . md5($email)) > self::RL_EMAIL_MAX) {
|
||||||
|
return 'You have started several quotes recently. Please try again later or contact us for help.';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function bump_counter(string $key): int {
|
||||||
|
$tkey = 'espinstanda_' . $key;
|
||||||
|
$n = (int) get_transient($tkey) + 1;
|
||||||
|
set_transient($tkey, $n, self::RL_WINDOW);
|
||||||
|
return $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------- failure surfacing */
|
||||||
|
|
||||||
|
private function alert_failure(Transaction $tx, ?Api_Result $result): void {
|
||||||
|
(new Notifier())->validation_failure_alert($tx, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** In-memory transaction used to alert when no row was stored (storage off / insert failed). */
|
||||||
|
private function synth_tx(array $form, array $values, string $dedupe, string $error): Transaction {
|
||||||
|
$tx = new Transaction();
|
||||||
|
$tx->form_id = (int) ($form['id'] ?? 0);
|
||||||
|
$tx->environment = Config::environment()->value;
|
||||||
|
$tx->dedupe_key = $dedupe;
|
||||||
|
$tx->customer_email = (string) ($values['customer_email'] ?? '');
|
||||||
|
$tx->role_label = (string) ($values['role'] ?? '');
|
||||||
|
$tx->error_detail = $error;
|
||||||
|
return $tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Best-effort admin alert when process() itself throws (F-11). Never throws. */
|
||||||
|
private function record_hard_failure(\Throwable $e): void {
|
||||||
|
try {
|
||||||
|
$tx = new Transaction();
|
||||||
|
$tx->environment = Config::environment()->value;
|
||||||
|
$tx->error_detail = 'Unexpected error during quote submission: ' . $e->getMessage();
|
||||||
|
(new Notifier())->validation_failure_alert($tx);
|
||||||
|
} catch (\Throwable $ignored) {
|
||||||
|
// never let the failure path itself throw
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ final class Transaction_Store {
|
|||||||
/** Write-ahead insert. Returns the new row id (0 on failure). */
|
/** Write-ahead insert. Returns the new row id (0 on failure). */
|
||||||
public function create_pending(Transaction $t): int {
|
public function create_pending(Transaction $t): int {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$now = current_time('mysql');
|
$now = current_time('mysql', true); // UTC - matches the gmdate() retention/dedupe cutoffs
|
||||||
$t->event_log[] = self::event('Write-ahead record created (status: pending)');
|
$t->event_log[] = self::event('Write-ahead record created (status: pending)');
|
||||||
|
|
||||||
$ok = $wpdb->insert(self::table_name(), [
|
$ok = $wpdb->insert(self::table_name(), [
|
||||||
@@ -159,14 +159,14 @@ final class Transaction_Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function mark_success(int $id, string $quote_ref, ?string $quote_url, ?int $http_status): void {
|
public function mark_success(int $id, string $quote_ref, ?string $quote_url, ?int $http_status): void {
|
||||||
$delivered = current_time('mysql');
|
$delivered = current_time('mysql', true); // UTC
|
||||||
$this->update($id, [
|
$this->update($id, [
|
||||||
'status' => Tx_Status::Delivered->value,
|
'status' => Tx_Status::Delivered->value,
|
||||||
'quote_ref' => $quote_ref,
|
'quote_ref' => $quote_ref,
|
||||||
'quote_url' => $quote_url,
|
'quote_url' => $quote_url,
|
||||||
'http_status' => $http_status,
|
'http_status' => $http_status,
|
||||||
'delivered_at' => $delivered,
|
'delivered_at' => $delivered,
|
||||||
'expiry' => $this->compute_expiry($delivered),
|
'expiry' => $this->compute_expiry(),
|
||||||
], 'Delivered - quoteRef ' . $quote_ref);
|
], 'Delivered - quoteRef ' . $quote_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,6 +251,22 @@ final class Transaction_Store {
|
|||||||
return $row ? Transaction::from_row($row) : null;
|
return $row ? Transaction::from_row($row) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Most recent delivered transaction for a content-addressed dedupe key within a window.
|
||||||
|
* Powers the cross-request duplicate guard: an identical submission that already
|
||||||
|
* delivered recently is reused instead of creating a second quote.
|
||||||
|
*/
|
||||||
|
public function recent_delivered_by_dedupe(string $dedupe_key, int $within_seconds): ?Transaction {
|
||||||
|
global $wpdb;
|
||||||
|
$table = self::table_name();
|
||||||
|
$cutoff = gmdate('Y-m-d H:i:s', time() - $within_seconds);
|
||||||
|
$row = $wpdb->get_row($wpdb->prepare(
|
||||||
|
"SELECT * FROM {$table} WHERE dedupe_key = %s AND status = %s AND delivered_at >= %s ORDER BY id DESC LIMIT 1",
|
||||||
|
$dedupe_key, Tx_Status::Delivered->value, $cutoff
|
||||||
|
), ARRAY_A);
|
||||||
|
return $row ? Transaction::from_row($row) : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paged list for the admin browser, scoped to the active environment.
|
* Paged list for the admin browser, scoped to the active environment.
|
||||||
*
|
*
|
||||||
@@ -308,19 +324,43 @@ final class Transaction_Store {
|
|||||||
/* ----------------------------------------------------------------- retention */
|
/* ----------------------------------------------------------------- retention */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purge ONLY delivered records past the retention window for the given env.
|
* Purge delivered records past the retention window for the given env, EXCEPT
|
||||||
* Pending/failed are never deleted on a timer. Returns the number removed.
|
* stranded leads (delivered but never attached to an entry) which must survive so a
|
||||||
|
* quote whose customer was never notified is not silently lost. Returns rows removed.
|
||||||
*/
|
*/
|
||||||
public function purge_delivered_older_than(int $days, Environment $env): int {
|
public function purge_delivered_older_than(int $days, Environment $env): int {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$table = self::table_name();
|
$table = self::table_name();
|
||||||
$cutoff = gmdate('Y-m-d H:i:s', time() - ($days * DAY_IN_SECONDS));
|
$cutoff = gmdate('Y-m-d H:i:s', time() - ($days * DAY_IN_SECONDS));
|
||||||
return (int) $wpdb->query($wpdb->prepare(
|
return (int) $wpdb->query($wpdb->prepare(
|
||||||
"DELETE FROM {$table} WHERE status = %s AND environment = %s AND delivered_at IS NOT NULL AND delivered_at < %s",
|
"DELETE FROM {$table} WHERE status = %s AND environment = %s AND entry_id IS NOT NULL AND delivered_at IS NOT NULL AND delivered_at < %s",
|
||||||
Tx_Status::Delivered->value, $env->value, $cutoff
|
Tx_Status::Delivered->value, $env->value, $cutoff
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scrub PII from unresolved (failed/pending) records older than the window while
|
||||||
|
* keeping the row for audit. Failed/pending rows are never timer-deleted, so without
|
||||||
|
* this their customer email/payload would be retained indefinitely. Returns rows scrubbed.
|
||||||
|
*/
|
||||||
|
public function anonymize_stale_unresolved(int $days): int {
|
||||||
|
global $wpdb;
|
||||||
|
$table = self::table_name();
|
||||||
|
$cutoff = gmdate('Y-m-d H:i:s', time() - ($days * DAY_IN_SECONDS));
|
||||||
|
return (int) $wpdb->query($wpdb->prepare(
|
||||||
|
"UPDATE {$table} SET customer_email = '', redacted_payload = '', response_excerpt = NULL
|
||||||
|
WHERE status IN ('failed', 'pending') AND customer_email <> '' AND created_at < %s",
|
||||||
|
$cutoff
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Data-subject erasure: remove every transaction for a customer email. Returns rows deleted. */
|
||||||
|
public function delete_by_email(string $email): int {
|
||||||
|
global $wpdb;
|
||||||
|
$table = self::table_name();
|
||||||
|
return (int) $wpdb->query($wpdb->prepare("DELETE FROM {$table} WHERE customer_email = %s", $email));
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- internals */
|
/* ----------------------------------------------------------------- internals */
|
||||||
|
|
||||||
private function update(int $id, array $data, ?string $event): void {
|
private function update(int $id, array $data, ?string $event): void {
|
||||||
@@ -335,14 +375,14 @@ final class Transaction_Store {
|
|||||||
$wpdb->update(self::table_name(), $data, ['id' => $id]);
|
$wpdb->update(self::table_name(), $data, ['id' => $id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function compute_expiry(string $delivered_at): string {
|
/** Expiry = now + retention window, in UTC (delivered_at is written at ~the same instant). */
|
||||||
|
private function compute_expiry(): string {
|
||||||
$days = (int) get_option('espinstanda_retention_days', 7);
|
$days = (int) get_option('espinstanda_retention_days', 7);
|
||||||
$ts = strtotime($delivered_at) ?: time();
|
return gmdate('Y-m-d H:i:s', time() + ($days * DAY_IN_SECONDS));
|
||||||
return gmdate('Y-m-d H:i:s', $ts + ($days * DAY_IN_SECONDS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{ts:string,level:string,message:string} */
|
/** @return array{ts:string,level:string,message:string} */
|
||||||
private static function event(string $message, string $level = 'info'): array {
|
private static function event(string $message, string $level = 'info'): array {
|
||||||
return ['ts' => current_time('mysql'), 'level' => $level, 'message' => Logger::redact($message)];
|
return ['ts' => current_time('mysql', true), 'level' => $level, 'message' => Logger::redact($message)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ final class Transactions_List_Table extends \WP_List_Table {
|
|||||||
|
|
||||||
protected function column_default($item, $column_name): string {
|
protected function column_default($item, $column_name): string {
|
||||||
return match ($column_name) {
|
return match ($column_name) {
|
||||||
'submitted' => esc_html($item->created_at) . '<br><span class="mono">#' . $item->id . '</span>',
|
'submitted' => esc_html(get_date_from_gmt($item->created_at, 'Y-m-d H:i')) . '<br><span class="mono">#' . $item->id . '</span>',
|
||||||
'email' => esc_html($item->customer_email),
|
'email' => esc_html($item->customer_email),
|
||||||
'role' => esc_html($item->role_label),
|
'role' => esc_html($item->role_label),
|
||||||
'status' => $this->status_badge($item),
|
'status' => $this->status_badge($item),
|
||||||
@@ -136,15 +136,21 @@ final class Resubmit_Handler {
|
|||||||
if ($tx === null) {
|
if ($tx === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ($tx->status === Tx_Status::Delivered->value) {
|
||||||
|
$store->append_event($tx_id, 'Resubmit blocked - already delivered (would duplicate the quote).', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ($tx->environment !== Config::environment()->value) {
|
if ($tx->environment !== Config::environment()->value) {
|
||||||
$store->append_event($tx_id, 'Resubmit blocked - cross-environment.', 'error');
|
$store->append_event($tx_id, 'Resubmit blocked - cross-environment.', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Self-recovery guard: skip if the customer already has a recent successful quote.
|
// Self-recovery guard: skip only when an IDENTICAL submission already delivered
|
||||||
$recent = $store->recent_success_for_email($tx->customer_email, DAY_IN_SECONDS);
|
// recently. Scoped to the content dedupe key so a customer's different event
|
||||||
|
// (different key) is never blocked.
|
||||||
|
$recent = $store->recent_delivered_by_dedupe($tx->dedupe_key, Submission::DEDUPE_WINDOW);
|
||||||
if ($recent !== null && $recent->id !== $tx->id) {
|
if ($recent !== null && $recent->id !== $tx->id) {
|
||||||
$store->append_event($tx_id, 'Resubmit skipped - customer already has a recent successful quote.');
|
$store->append_event($tx_id, 'Resubmit skipped - an identical submission already has a recent quote.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,14 +159,24 @@ final class Resubmit_Handler {
|
|||||||
$store->append_event($tx_id, 'Resubmit aborted - stored payload unreadable.', 'error');
|
$store->append_event($tx_id, 'Resubmit aborted - stored payload unreadable.', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Trust boundary: the stored body is untrusted input on the way back out to the
|
||||||
|
// insurer - re-validate it before re-sending (guards against DB tampering).
|
||||||
|
$payload_errors = (new Field_Mapper())->validate_payload($body);
|
||||||
|
if ($payload_errors) {
|
||||||
|
$store->append_event($tx_id, 'Resubmit aborted - stored payload failed re-validation: ' . implode(', ', $payload_errors), 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$store->increment_retry($tx_id); // this attempt is a retry - keep the count truthful
|
||||||
|
|
||||||
$result = (new Api_Client())->start_quote($body, $tx->dedupe_key);
|
$result = (new Api_Client())->start_quote($body, $tx->dedupe_key);
|
||||||
if ($result->ok && $result->quote_ref !== null) {
|
if ($result->ok && $result->quote_ref !== null && $result->quote_ref !== '') {
|
||||||
$store->mark_success($tx_id, $result->quote_ref, $result->url_single_use, $result->http_status);
|
$store->mark_success($tx_id, $result->quote_ref, $result->url_single_use, $result->http_status);
|
||||||
Failure_Surface::bump();
|
Failure_Surface::bump();
|
||||||
|
|
||||||
if ($tx->entry_id) {
|
if ($tx->entry_id) {
|
||||||
Entry_Integration::record($tx->entry_id, $result->quote_ref, (string) $result->url_single_use, 'delivered', $tx->environment);
|
Entry_Integration::record($tx->entry_id, $result->quote_ref, (string) $result->url_single_use, 'delivered', $tx->environment);
|
||||||
|
self::notify_resubmit_success((int) $tx->entry_id);
|
||||||
} else {
|
} else {
|
||||||
// Stranded lead (no entry) - mint a fresh link and email the customer (option B).
|
// Stranded lead (no entry) - mint a fresh link and email the customer (option B).
|
||||||
$fresh = (string) $result->url_single_use;
|
$fresh = (string) $result->url_single_use;
|
||||||
@@ -176,4 +192,19 @@ final class Resubmit_Handler {
|
|||||||
Failure_Surface::bump();
|
Failure_Surface::bump();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Dispatch the registered espinstanda_resubmit_success notification event for an entry. */
|
||||||
|
private static function notify_resubmit_success(int $entry_id): void {
|
||||||
|
if (!class_exists('\GFAPI')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$entry = \GFAPI::get_entry($entry_id);
|
||||||
|
if (is_wp_error($entry)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$form = \GFAPI::get_form((int) $entry['form_id']);
|
||||||
|
if ($form) {
|
||||||
|
\GFAPI::send_notifications($form, $entry, 'espinstanda_resubmit_success');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
=== ESP INSTANDA Start Quote Integration ===
|
||||||
|
Contributors: getfused
|
||||||
|
Requires at least: 7.0
|
||||||
|
Requires PHP: 8.5
|
||||||
|
Stable tag: 1.1.0
|
||||||
|
|
||||||
|
Pushes Gravity Forms "Start a Quote" submissions into INSTANDA's Package API with
|
||||||
|
write-ahead transaction logging, native entry recording, admin resubmit, and a test-mode lock.
|
||||||
|
|
||||||
|
== Changelog ==
|
||||||
|
|
||||||
|
= 1.1.0 =
|
||||||
|
Remediation of the 2026-07 security/reliability/PII audit (see docs/audit-esp-instanda-2026-07.md).
|
||||||
|
|
||||||
|
No duplicate policies / no lost quotes:
|
||||||
|
* Dedupe key is now content-addressed (form id + mapped field values) instead of a
|
||||||
|
per-request token, so an identical re-POST or a retry-after-error reuses the existing
|
||||||
|
quote instead of creating a second one at INSTANDA (F-01). Adds a 30-minute
|
||||||
|
short-circuit window and a content-key race lock.
|
||||||
|
* Refuse to resubmit an already-delivered transaction (F-12); scope the resubmit
|
||||||
|
self-recovery guard to the content dedupe key so a customer's *different* event is not
|
||||||
|
skipped (F-18).
|
||||||
|
* A 2xx response with a missing/empty quoteRef is now recorded as ambiguous
|
||||||
|
(possible_duplicate = 1), not a hard failure (F-10, F-17).
|
||||||
|
* Aborts the StartQuote when the write-ahead insert fails, so no unaudited call is made (F-14).
|
||||||
|
|
||||||
|
Go-live safety:
|
||||||
|
* switch_to_live() now also sets the environment to Live; previously the go-live button
|
||||||
|
left real quotes hitting the Test endpoint (F-03).
|
||||||
|
* Go-live advisory flags when more than one active INSTANDA feed exists (F-02).
|
||||||
|
|
||||||
|
Security & PII:
|
||||||
|
* Corrected the at-rest-secret docblock: the "DB dump never exposes a secret" guarantee
|
||||||
|
only holds when SPG_INSTANDA_KEY is set as a constant (F-04).
|
||||||
|
* Retention now scrubs PII from stale failed/pending rows (previously kept forever) and
|
||||||
|
exempts stranded delivered leads from the purge (F-05, F-13); wired WordPress's Erase
|
||||||
|
Personal Data tool to delete a customer's transactions (F-05).
|
||||||
|
* Uninstall now removes ALL plugin options and transients, including the encrypted
|
||||||
|
password and its key (F-15).
|
||||||
|
* Added per-IP (20/h) and per-email (5/h) rate limiting on the public create (F-06).
|
||||||
|
|
||||||
|
Reliability & correctness:
|
||||||
|
* Timestamps are written in UTC to match the retention/dedupe cutoffs and displayed in
|
||||||
|
site-local time (F-07). NOTE: rows created before 1.1.0 were stored in site-local time;
|
||||||
|
clear the transaction table (test data) at deploy to avoid a mixed-timezone history.
|
||||||
|
* Fail closed on an unexpected error in the create path (no quote-less entry) and alert
|
||||||
|
admins, instead of silently passing (F-11); log when async recording cannot resolve a
|
||||||
|
transaction (F-09).
|
||||||
|
* The "Gravity Forms required" admin notice is now shown even when Gravity Forms is
|
||||||
|
inactive (F-16); the daily retention cron self-heals on admin_init (F-22).
|
||||||
|
* Resubmit re-validates the stored payload before re-sending (F-19); the Retries count is
|
||||||
|
now incremented and the resubmit-success notification event is dispatched (F-20).
|
||||||
|
|
||||||
|
Theme:
|
||||||
|
* The Form-5 date-range inline JS is emitted only on pages that embed a Gravity Form and
|
||||||
|
its MutationObserver now disconnects instead of watching the DOM forever (F-23).
|
||||||
|
|
||||||
|
Operations required alongside this release (see the audit report, Ops checklist):
|
||||||
|
* Set SPG_INSTANDA_KEY + SPG_INSTANDA_USERNAME_LIVE/_PASSWORD_LIVE + SPG_INSTANDA_ENV in
|
||||||
|
production wp-config.php (blocking) - OPS-1 / F-04.
|
||||||
|
* Deactivate the INSTANDA feed on the test Form 6 in production (blocking) - OPS-3 / F-02.
|
||||||
|
* Configure espinstanda_alert_emails and the quote-success notification (blocking) - OPS-4.
|
||||||
|
* Rotate the SendGrid API key out of committed wp-config.php - OPS-2 / F-08.
|
||||||
|
* Add reCAPTCHA/Akismet to the canonical quote form - OPS-5 / F-06.
|
||||||
|
|
||||||
|
= 1.0.7 =
|
||||||
|
* Initial audited release.
|
||||||
@@ -20,10 +20,19 @@ try {
|
|||||||
// Table name is a trusted internal constant, not user input.
|
// Table name is a trusted internal constant, not user input.
|
||||||
$wpdb->query("DROP TABLE IF EXISTS {$table}");
|
$wpdb->query("DROP TABLE IF EXISTS {$table}");
|
||||||
|
|
||||||
delete_option('espinstanda_db_version');
|
// Remove EVERY plugin option and transient - including the encrypted Test password
|
||||||
delete_option('espinstanda_operating_mode_audit');
|
// and its self-provisioned key - so no recoverable secret survives uninstall.
|
||||||
|
$opt = $wpdb->esc_like('espinstanda_') . '%';
|
||||||
|
$tr = '_transient_' . $wpdb->esc_like('espinstanda_') . '%';
|
||||||
|
$trt = '_transient_timeout_' . $wpdb->esc_like('espinstanda_') . '%';
|
||||||
|
$wpdb->query($wpdb->prepare(
|
||||||
|
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s",
|
||||||
|
$opt,
|
||||||
|
$tr,
|
||||||
|
$trt
|
||||||
|
));
|
||||||
|
|
||||||
// Clear any scheduled cleanup that may still be queued.
|
// Clear any scheduled events that may still be queued.
|
||||||
wp_clear_scheduled_hook('esp_instanda_cleanup');
|
wp_clear_scheduled_hook('esp_instanda_cleanup');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
if (function_exists('error_log')) {
|
if (function_exists('error_log')) {
|
||||||
|
|||||||
@@ -189,7 +189,17 @@ function gf_validate_date_range( $validation_result ) {
|
|||||||
add_action( 'wp_footer', 'gf_date_range_scripts' );
|
add_action( 'wp_footer', 'gf_date_range_scripts' );
|
||||||
|
|
||||||
function gf_date_range_scripts() {
|
function gf_date_range_scripts() {
|
||||||
if ( ! class_exists( 'GFForms' ) ) {
|
if ( ! class_exists( 'GFForms' ) || is_admin() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Only emit this inline script on requests whose content embeds a Gravity Form -
|
||||||
|
// keeps ~220 lines of JS off every other page. Server-side validation is unaffected.
|
||||||
|
// If the post cannot be inspected, fall back to emitting (safe default).
|
||||||
|
$post = get_post();
|
||||||
|
if ( $post instanceof WP_Post
|
||||||
|
&& ! has_shortcode( (string) $post->post_content, 'gravityform' )
|
||||||
|
&& ! has_block( 'gravityforms/form', $post )
|
||||||
|
&& false === strpos( (string) $post->post_content, 'gform' ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -410,10 +420,14 @@ function gf_date_range_scripts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( ! attachListeners() ) {
|
if ( ! attachListeners() ) {
|
||||||
|
var tries = 0;
|
||||||
var observer = new MutationObserver( function () {
|
var observer = new MutationObserver( function () {
|
||||||
if ( attachListeners() ) observer.disconnect();
|
// Stop once the fields are wired, or after a bounded number of tries, so we
|
||||||
|
// never observe the whole document subtree indefinitely on non-form pages.
|
||||||
|
if ( attachListeners() || ++tries > 20 ) observer.disconnect();
|
||||||
} );
|
} );
|
||||||
observer.observe( document.body, { childList: true, subtree: true } );
|
observer.observe( document.body, { childList: true, subtree: true } );
|
||||||
|
setTimeout( function () { observer.disconnect(); }, 10000 );
|
||||||
}
|
}
|
||||||
|
|
||||||
} )();
|
} )();
|
||||||
|
|||||||
Reference in New Issue
Block a user