diff --git a/libs/website/feature/contactpage/constants/types/contact.constants.ts b/libs/website/feature/contactpage/constants/types/contact.constants.ts
new file mode 100644
index 000000000..1945b9187
--- /dev/null
+++ b/libs/website/feature/contactpage/constants/types/contact.constants.ts
@@ -0,0 +1,8 @@
+import type { FormData } from '../types/contact.types'
+
+export const DEFAULT_FORM_DATA: FormData = {
+ name: '',
+ email: '',
+ subject: '',
+ message: '',
+}
diff --git a/libs/website/feature/contactpage/constants/types/contact.types.ts b/libs/website/feature/contactpage/constants/types/contact.types.ts
new file mode 100644
index 000000000..60e8495c5
--- /dev/null
+++ b/libs/website/feature/contactpage/constants/types/contact.types.ts
@@ -0,0 +1,13 @@
+export interface FormData {
+ name: string
+ email: string
+ subject: string
+ message: string
+}
+
+export interface FormErrors {
+ name?: string
+ email?: string
+ subject?: string
+ message?: string
+}
diff --git a/libs/website/feature/contactpage/contactFormValidation.ts b/libs/website/feature/contactpage/contactFormValidation.ts
new file mode 100644
index 000000000..9d2f38af5
--- /dev/null
+++ b/libs/website/feature/contactpage/contactFormValidation.ts
@@ -0,0 +1,48 @@
+export interface FormData {
+ name: string
+ email: string
+ subject: string
+ message: string
+}
+
+export interface FormErrors {
+ name?: string
+ email?: string
+ subject?: string
+ message?: string
+}
+
+export function validateForm(values: FormData): FormErrors {
+ const errors: FormErrors = {}
+
+ /* Name validation */
+ if (!values.name.trim()) {
+ errors.name = 'Name is required'
+ }
+ else if (values.name.length < 2) {
+ errors.name = 'Name must be at least 2 characters'
+ }
+ /* Email validation */
+ if (!values.email) {
+ errors.email = 'Email is required'
+ }
+ else if (!/^[\w.%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
+ errors.email = 'Invalid email address'
+ }
+ /* Subject validation */
+ if (!values.subject.trim()) {
+ errors.subject = 'Subject is required'
+ }
+ else if (values.subject.length < 3) {
+ errors.subject = 'Subject must be at least 3 characters'
+ }
+ /* Message validation */
+ if (!values.message.trim()) {
+ errors.message = 'Message is required'
+ }
+ else if (values.message.length < 10) {
+ errors.message = 'Message must be at least 10 characters'
+ }
+
+ return errors
+}
diff --git a/libs/website/feature/contactpage/index.tsx b/libs/website/feature/contactpage/index.tsx
new file mode 100644
index 000000000..44d1b65a7
--- /dev/null
+++ b/libs/website/feature/contactpage/index.tsx
@@ -0,0 +1,62 @@
+import cuHackingLogo from '@cuhacking/shared/assets/logos/cuHacking/cuhacking-logo-1.svg'
+import { GlassmorphicCard } from '@cuhacking/shared/ui/src/cuHacking/components/glassmorphic-card'
+import React, { useEffect, useState } from 'react'
+import { ContactForm } from './ui/ContactForm'
+import { ContactHero } from './ui/ContactHero'
+import { StatusMessage } from './ui/StatusMessage'
+
+export function ContactPage(): React.JSX.Element {
+ const [submitStatus, setSubmitStatus] = useState<'success' | 'error' | null>(null)
+
+ // hiding message after 3 seconds
+ useEffect(() => {
+ if (submitStatus) {
+ const timer = setTimeout(() => {
+ setSubmitStatus(null)
+ }, 3000)
+
+ return () => clearTimeout(timer)
+ }
+ }, [submitStatus])
+
+ const handleSubmit = (status: 'success' | 'error') => {
+ setSubmitStatus(null)
+ setTimeout(() => {
+ setSubmitStatus(status)
+ }, 100)
+ }
+
+ return (
+
+
+
+
+ {/* Hero */}
+
+
+ {/* Status Message */}
+ {submitStatus && (
+
+
+
+ )}
+
+ {/* Form */}
+
+
+
+ {/* Logo */}
+
+
+
+
+
+
+ )
+}
diff --git a/libs/website/feature/contactpage/ui/ContactForm.tsx b/libs/website/feature/contactpage/ui/ContactForm.tsx
new file mode 100644
index 000000000..bba1e8c19
--- /dev/null
+++ b/libs/website/feature/contactpage/ui/ContactForm.tsx
@@ -0,0 +1,128 @@
+import type { FormData, FormErrors } from '../types/contact.types'
+import React, { useState } from 'react'
+import { validateForm } from '../contactFormValidation'
+
+interface ContactFormProps {
+ onSubmit: (status: 'success' | 'error') => void
+}
+
+export function ContactForm({ onSubmit }: ContactFormProps): React.JSX.Element {
+ const [formData, setFormData] = useState({
+ name: '',
+ email: '',
+ subject: '',
+ message: '',
+ })
+
+ const [errors, setErrors] = useState({})
+ const [isLoading, setIsLoading] = useState(false)
+
+ const handleChange = (
+ e: React.ChangeEvent,
+ ): void => {
+ const { name, value } = e.target
+
+ setFormData((prev: FormData) => ({
+ ...prev,
+ [name]: value,
+ }))
+
+ // Cleaning errors as user types
+ if (errors[name as keyof FormErrors]) {
+ setErrors((prev: FormErrors) => ({
+ ...prev,
+ [name]: undefined,
+ }))
+ }
+ }
+
+ const handleSubmit = async (e: React.FormEvent): Promise => {
+ e.preventDefault()
+
+ const validationErrors = validateForm(formData)
+ if (Object.keys(validationErrors).length > 0) {
+ setErrors(validationErrors)
+ return
+ }
+
+ setIsLoading(true)
+
+ try {
+ await new Promise((resolve) => {
+ setTimeout(resolve, 1500)
+ })
+ onSubmit('success')
+ setFormData({ name: '', email: '', subject: '', message: '' })
+ }
+ catch (error) {
+ console.error('Submission error:', error)
+ onSubmit('error')
+ }
+ finally {
+ setIsLoading(false)
+ }
+ }
+
+ return (
+
+ )
+}
diff --git a/libs/website/feature/contactpage/ui/ContactHero.tsx b/libs/website/feature/contactpage/ui/ContactHero.tsx
new file mode 100644
index 000000000..6d1a4f17f
--- /dev/null
+++ b/libs/website/feature/contactpage/ui/ContactHero.tsx
@@ -0,0 +1,17 @@
+import { TerminalText } from '@cuhacking/shared/ui/src/cuHacking/components/terminal-text'
+import React from 'react'
+
+export function ContactHero(): React.JSX.Element {
+ return (
+
+
+ Contact Us
+
+
+
+ Feel free to ask us anything! We’re here to help.
+
+
+
+ )
+}
diff --git a/libs/website/feature/contactpage/ui/StatusMessage.tsx b/libs/website/feature/contactpage/ui/StatusMessage.tsx
new file mode 100644
index 000000000..35dcc49ab
--- /dev/null
+++ b/libs/website/feature/contactpage/ui/StatusMessage.tsx
@@ -0,0 +1,29 @@
+import React from 'react'
+
+interface StatusMessageProps {
+ type: 'success' | 'error'
+}
+
+export function StatusMessage({ type }: StatusMessageProps): React.JSX.Element {
+ return (
+
+ {/* Icon */}
+
+ {type === 'success' ? '✅' : '❌'}
+
+
+ {/* Message */}
+
+ {type === 'success'
+ ? 'Message sent successfully!'
+ : 'Failed to send message. Please try again.'}
+
+
+ )
+}
diff --git a/libs/website/pages/home.tsx b/libs/website/pages/home.tsx
index 76a3302ae..07b715a23 100644
--- a/libs/website/pages/home.tsx
+++ b/libs/website/pages/home.tsx
@@ -1,8 +1,10 @@
import React from 'react'
+import { ContactPage } from '../feature/contactpage'
import { EventSection } from '../feature/events'
import { FAQSection } from '../feature/faq'
import { MissionSection, WelcomeSection } from '../feature/introduction'
import { SponsorshipSection } from '../feature/sponsorship'
+
import { Layout } from '../layouts/base'
export function Home() {
@@ -13,6 +15,7 @@ export function Home() {
+
)
}
diff --git a/libs/website/shared/ui/navigation/navbar/constants/navbar.constants.ts b/libs/website/shared/ui/navigation/navbar/constants/navbar.constants.ts
index f8d663877..66d212fb6 100644
--- a/libs/website/shared/ui/navigation/navbar/constants/navbar.constants.ts
+++ b/libs/website/shared/ui/navigation/navbar/constants/navbar.constants.ts
@@ -14,6 +14,7 @@ const links = [
{ name: 'EVENTS', link: '/#events' },
{ name: 'SPONSORS', link: '/#sponsors' },
{ name: 'FAQ', link: '/#faq' },
+ { name: 'CONTACT US', link: '/#contactpage' },
]
const socials = [
diff --git a/tools/risk-form-filler/eslint.config.js b/tools/risk-form-filler/eslint.config.js
new file mode 100644
index 000000000..2015c83a8
--- /dev/null
+++ b/tools/risk-form-filler/eslint.config.js
@@ -0,0 +1,16 @@
+import playwright from 'eslint-plugin-playwright'
+import baseConfigPromise from '../../eslint.config.js'
+
+export default (async () => {
+ const baseConfig = await baseConfigPromise
+
+ return [
+ playwright.configs['flat/recommended'],
+ ...baseConfig,
+ {
+ files: ['**/*.ts', '**/*.js'],
+ // Override or add rules here
+ rules: {},
+ },
+ ]
+})()
diff --git a/tools/risk-form-filler/package.json b/tools/risk-form-filler/package.json
new file mode 100644
index 000000000..5e3057021
--- /dev/null
+++ b/tools/risk-form-filler/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "risk-form-filler",
+ "type": "module",
+ "description": "",
+ "license": "",
+ "sideEffects": false,
+ "scripts": {}
+}
diff --git a/tools/risk-form-filler/playwright.config.ts b/tools/risk-form-filler/playwright.config.ts
new file mode 100644
index 000000000..530f42224
--- /dev/null
+++ b/tools/risk-form-filler/playwright.config.ts
@@ -0,0 +1,45 @@
+// TODO: Investigate node global process usage
+
+import { fileURLToPath } from 'node:url'
+import { nxE2EPreset } from '@nx/playwright/preset'
+
+import { defineConfig, devices } from '@playwright/test'
+
+const __filename = fileURLToPath(import.meta.url)
+
+// // For CI, you may want to set BASE_URL to the deployed application.
+// const baseURL = process.env.BASE_URL || 'http://127.0.0.1:3000'
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+// require('dotenv').config();
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+export default defineConfig({
+ ...nxE2EPreset(__filename, { testDir: './src' }),
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ retries: 2,
+ use: {
+ // baseURL,
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry',
+ },
+ /* Run your local dev server before starting the tests */
+ // webServer: {
+ // command: 'pnpm nx start risk-form-filler',
+ // // url: 'http://127.0.0.1:3000',
+ // // reuseExistingServer: !process.env.CI,
+ // cwd: workspaceRoot,
+ // timeout: 120 * 1000,
+ // },
+ projects: [
+ {
+ name: 'chromium (desktop)',
+ use: { ...devices['Desktop Chrome'] },
+ },
+ ],
+})
diff --git a/tools/risk-form-filler/project.json b/tools/risk-form-filler/project.json
new file mode 100644
index 000000000..01ad037f8
--- /dev/null
+++ b/tools/risk-form-filler/project.json
@@ -0,0 +1,28 @@
+{
+ "name": "risk-form-filler",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "tools/risk-form-filler",
+ "projectType": "application",
+ "tags": [],
+ "// targets": "to see all targets run: nx show project risk-form-filler --web",
+ "targets": {
+ "online": {
+ "command": "npx tsx src/input/online-input.ts",
+ "options": {
+ "cwd": "tools/risk-form-filler"
+ }
+ },
+ "in-person": {
+ "command": "npx tsx src/input/in-person-input.ts",
+ "options": {
+ "cwd": "tools/risk-form-filler"
+ }
+ },
+ "hybrid": {
+ "command": "npx tsx src/input/hybrid-input.ts",
+ "options": {
+ "cwd": "tools/risk-form-filler"
+ }
+ }
+ }
+}
diff --git a/tools/risk-form-filler/src/defs/online-input-defs.ts b/tools/risk-form-filler/src/defs/online-input-defs.ts
new file mode 100644
index 000000000..57460bdf4
--- /dev/null
+++ b/tools/risk-form-filler/src/defs/online-input-defs.ts
@@ -0,0 +1,6 @@
+export interface ScheduleOnlineParams {
+ name: string
+ email: string
+ subject: string
+ message: string
+}
diff --git a/tools/risk-form-filler/src/input/online-input.ts b/tools/risk-form-filler/src/input/online-input.ts
new file mode 100644
index 000000000..3883dd6d7
--- /dev/null
+++ b/tools/risk-form-filler/src/input/online-input.ts
@@ -0,0 +1,20 @@
+import type { ScheduleOnlineParams } from '../defs/online-input-defs'
+import { chromium } from '@playwright/test'
+import { scheduleOnline } from '../online'
+import { FormsLayout } from '../pom'
+
+(async function getInputAndRunPlaywright() {
+ const params: ScheduleOnlineParams = {
+ name: '¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!',
+ email: 'getpwned@gmail.com',
+ subject: '¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!',
+ message: '¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!¡getpwned!',
+ }
+
+ const browser = await chromium.launch({ headless: false })
+ const page = await browser.newPage()
+ const formLayout = new FormsLayout(page)
+ for (let i = 0; i < 100; i++) {
+ await scheduleOnline(params, formLayout)
+ }
+})()
diff --git a/tools/risk-form-filler/src/online.ts b/tools/risk-form-filler/src/online.ts
new file mode 100644
index 000000000..0d32e44ce
--- /dev/null
+++ b/tools/risk-form-filler/src/online.ts
@@ -0,0 +1,9 @@
+import type { ScheduleOnlineParams } from './input/schedule-online-params'
+
+import type { FormsLayout } from './pom'
+
+export async function scheduleOnline(params: ScheduleOnlineParams, formLayout: FormsLayout) {
+ await formLayout.goto()
+ await formLayout.fillContactPage(formLayout, params.name, params.email, params.subject, params.message)
+ await formLayout.submitButton.click()
+}
diff --git a/tools/risk-form-filler/src/pom.ts b/tools/risk-form-filler/src/pom.ts
new file mode 100644
index 000000000..fe417be20
--- /dev/null
+++ b/tools/risk-form-filler/src/pom.ts
@@ -0,0 +1,38 @@
+import type { Locator, Page } from '@playwright/test'
+
+export class FormsLayout {
+ // Page object
+ readonly page: Page
+
+ // textboxes
+ readonly nameTextBox: Locator
+ readonly emailTextBox: Locator
+ readonly subjectTextBox: Locator
+ readonly messageTextBox: Locator
+
+ // buttons
+ readonly submitButton: Locator
+
+ constructor(page: Page) {
+ this.page = page
+
+ this.nameTextBox = page.getByPlaceholder('Your Name')
+ this.emailTextBox = page.getByPlaceholder('Your Email')
+ this.subjectTextBox = page.getByPlaceholder('Subject')
+ this.messageTextBox = page.getByPlaceholder('Your Message')
+
+ this.submitButton = page.getByRole('button', { name: 'Send Message' })
+ }
+
+ // goto
+ async goto() {
+ await this.page.goto('http://localhost:3000/#contactpage')
+ }
+
+ async fillContactPage(formLayout: FormsLayout, NAME: string, EMAIL: string, SUBJECT: string, MESSAGE: string) {
+ await formLayout.nameTextBox.fill(NAME)
+ await formLayout.emailTextBox.fill(EMAIL)
+ await formLayout.subjectTextBox.fill(SUBJECT)
+ await formLayout.messageTextBox.fill(MESSAGE)
+ }
+}
diff --git a/tools/risk-form-filler/tsconfig.json b/tools/risk-form-filler/tsconfig.json
new file mode 100644
index 000000000..76cca2543
--- /dev/null
+++ b/tools/risk-form-filler/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "moduleResolution": "node",
+ "outDir": "../../dist/out-tsc",
+ "esModuleInterop": true
+ },
+ "include": [
+ "**/*.ts",
+ "**/*.js",
+ "playwright.config.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.spec.js",
+ "src/**/*.test.ts",
+ "src/**/*.test.js",
+ "src/**/*.d.ts"
+ ]
+}