diff --git a/.gitignore b/.gitignore index 5390e37..3f45fa8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -api node_modules/ .env.* database/data.db diff --git a/api/Dockerfile b/api/Dockerfile new file mode 100644 index 0000000..81eb82e --- /dev/null +++ b/api/Dockerfile @@ -0,0 +1,38 @@ +# syntax = docker/dockerfile:1 + +FROM oven/bun:1.2.12-slim as base + +LABEL fly_launch_runtime="Bun" + +# NodeJS app lives here +WORKDIR /app + +# Set production environment +ENV NODE_ENV=production + + +# Throw-away build stage to reduce size of final image +FROM base as build + +# Install packages needed to build node modules +RUN apt-get update -qq && \ + apt-get install -y python-is-python3 pkg-config build-essential + +# Install node modules +COPY --link package.json . +RUN bun install --production + +# Copy application code +COPY --link . . + +# Final stage for app image +FROM base + +# Copy built application +COPY --from=build /app /app + +RUN apt-get update && apt-get install -y sqlite3 && rm -rf /var/lib/apt/lists/* + +# Start the server by default, this can be overwritten at runtime +CMD [ "bun", "run", "db:seed:prod" ] +CMD [ "bun", "run", "start" ] diff --git a/api/bun.lock b/api/bun.lock new file mode 100644 index 0000000..af2db4f --- /dev/null +++ b/api/bun.lock @@ -0,0 +1,19 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "devDependencies": { + "@types/bun": "^1.2.11", + }, + }, + }, + "packages": { + "@types/bun": ["@types/bun@1.2.11", "", { "dependencies": { "bun-types": "1.2.11" } }, "sha512-ZLbbI91EmmGwlWTRWuV6J19IUiUC5YQ3TCEuSHI3usIP75kuoA8/0PVF+LTrbEnVc8JIhpElWOxv1ocI1fJBbw=="], + + "@types/node": ["@types/node@22.15.3", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw=="], + + "bun-types": ["bun-types@1.2.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-dbkp5Lo8HDrXkLrONm6bk+yiiYQSntvFUzQp0v3pzTAsXk6FtgVMjdQ+lzFNVAmQFUkPQZ3WMZqH5tTo+Dp/IA=="], + + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + } +} diff --git a/api/calculator/calc.ts b/api/calculator/calc.ts new file mode 100644 index 0000000..0479678 --- /dev/null +++ b/api/calculator/calc.ts @@ -0,0 +1,255 @@ +import { activities, Activity, Attribute, attributes, BenchmarkPerformance, findNearestPoints, Gender, getActivityAttribute, kgToLb, Levels, msToTime, StandardsItem } from "./util"; +import rawStandards from "./data/standards.json" assert { type: "json" } + +const standards = rawStandards as StandardsItem[]; + +// SOURCES +// Squat, Bench, Dead Lift: +// http://lonkilgore.com/resources/Lon_Kilgore_Strength_Standard_Tables-Copyright-2023.pdf +// 1 mile run: +// https://runninglevel.com/running-times/1-mile-times +// Dash: +// https://marathonhandbook.com/average-100-meter-time/ +// Broad Jump: +// + + +// ------------------------------------------------------------------------------------------------- +// Level calculations +// ------------------------------------------------------------------------------------------------- +export const calcBenchmarkLevel = (performance: number, levels: Record): number => { + let playerLevel = 1; + let playerLevelDiff = Infinity; + + for (const level in levels) { + const diff = Math.abs(performance - levels[level as unknown as number]); + if (diff < playerLevelDiff) { + playerLevel = +level; + playerLevelDiff = diff; + } + } + return playerLevel; +}; + +export const calcAttributeLevel = ( + attribute: Attribute, + benchmarkPerformances: BenchmarkPerformance[], +): number => { + if (benchmarkPerformances.some((bp) => getActivityAttribute(bp.activity) !== attribute)) { + throw new Error("Wrong benchmark performance attribute"); + } + + const benchmarkLevels = benchmarkPerformances.map((abp) => + calcBenchmarkLevel(abp.performance, abp.levels), + ); + + const benchmarkLevelsAvg = Math.round( + benchmarkLevels.reduce((sum, curr) => sum + curr, 0) / benchmarkLevels.length, + ); + + return benchmarkLevelsAvg; +}; + +export const calcAttributeLevels = ( + benchmarkPerformances: BenchmarkPerformance[], +): Record => { + const attrLevels: Record = { + [attributes.STRENGTH]: 1, + [attributes.POWER]: 1, + [attributes.ENDURANCE]: 1, + [attributes.SPEED]: 1, + [attributes.AGILITY]: 1, + } as const; + + (Object.values(attributes) as Attribute[]).forEach((attribute) => { + const attrBenchmarkPerformances = benchmarkPerformances.filter( + (bp) => getActivityAttribute(bp.activity) === attribute, + ); + attrLevels[attribute] = calcAttributeLevel(attribute, attrBenchmarkPerformances); + }); + + return attrLevels; +}; + +export const calcPlayerLevel = (benchmarkPerformances: BenchmarkPerformance[]): number => { + const attrLevels = calcAttributeLevels(benchmarkPerformances); + const attrLevelsSum = Object.values(attrLevels).reduce((sum, lvl) => sum + lvl, 0); + return Math.round(attrLevelsSum / Object.keys(attributes).length); +}; + +// ------------------------------------------------------------------------------------------------- +// Presentation helpers +// ------------------------------------------------------------------------------------------------- +export const formatLevelValues = ( + levels: Record, + activity: Activity, +): Record => { + const timedActivities: Activity[] = [activities.RUN, activities.DASH, activities.CONE_DRILL]; + + const formattedLevels: Record = {}; + for (const level in levels) { + const lvl = +level as number; + let displayValue = ""; + if (timedActivities.includes(activity)) { + displayValue = msToTime(levels[lvl]); + } else if (activity === activities.TREADMILL_DASH) { + displayValue = `${(levels[lvl] * 1000).toFixed(2)} m/s`; + } else if (activity === activities.BROAD_JUMP) { + displayValue = `${(levels[lvl] * 0.0328084).toFixed(2)} ft.`; + } else { + displayValue = kgToLb(levels[lvl]).toFixed(0); + } + + formattedLevels[lvl] = displayValue; + } + + return formattedLevels; +}; + +// ------------------------------------------------------------------------------------------------- +// Level utilities +// ------------------------------------------------------------------------------------------------- +const compressLevels = ( + levels: Record, + targetLevelsAmount: number, +): Record => { + const levelsAmount = Object.keys(levels).length; + if (levelsAmount < targetLevelsAmount) { + throw new Error( + "Target levels amount must be greater than or equal to the current levels amount", + ); + } + + const ratio = levelsAmount / targetLevelsAmount; + const compressedLevels: Record = {}; + + for (let i = 0; i < targetLevelsAmount; ++i) { + const ratioIndex = i * ratio; + const lowerIndex = Math.floor(ratioIndex); + const upperIndex = Math.ceil(ratioIndex); + + const lowerValue = levels[lowerIndex + 1]; + const upperValue = levels[upperIndex + 1]; + + const weight = ratioIndex - lowerIndex; + compressedLevels[i + 1] = lowerValue + (upperValue - lowerValue) * weight; + } + + return compressedLevels; +}; + +const expandLevels = ( + levels: Levels | Record, + i: number +): Record => { + if (i == 0) { + // ensure we always use number keys + const newLevels = {}; + for (let k = 0; k < Object.keys(levels).length; ++k) { + newLevels[k + 1] = levels[Object.keys(levels)[k]]; + } + return newLevels; + }; + + const newLevels = {}; + let j = 1; + for (let k = 0; k < Object.keys(levels).length; ++k) { + const currLevel = Object.keys(levels)[k]; + const nextLevel = Object.keys(levels)[k + 1]; + + newLevels[j++] = levels[currLevel]; + + if (nextLevel) { + newLevels[j++] = (levels[currLevel] + levels[nextLevel]) / 2; + } + } + + return expandLevels(newLevels, i - 1); +} + +// ------------------------------------------------------------------------------------------------- +// Main level function +// ------------------------------------------------------------------------------------------------- +export const computeLevels = ( + age: number, + weightKG: number, + gender: Gender, + activity: Activity, +) => { + const levels = calculateLevels(age, weightKG, gender, activity, standards); + if (levels) { + const expandedLevels = expandLevels(levels, 5); + const compressedLevels = compressLevels(expandedLevels, 100); + return compressedLevels; + } else { + return {}; + } +} + +// ------------------------------------------------------------------------------------------------- +// Standards interpolation (heavy math bits) +// ------------------------------------------------------------------------------------------------- +const calculateLevels = ( + age: number, + weightKG: number, + gender: Gender, + activity: Activity, + standards: StandardsItem[], +): Levels | null => { + // Filter dataset + const filtered = standards.filter( + (item) => item.gender === gender && item.activityType === activity, + ); + if (filtered.length === 0) return null; + + // Age interpolation + const ageArray = [...new Set(filtered.map((s) => s.age))].sort((a, b) => a - b); + const { lower: ageLower, upper: ageUpper } = findNearestPoints(age, ageArray); + + const lowerValues = interpolateByBodyWeight(ageLower, weightKG, filtered); + const upperValues = interpolateByBodyWeight(ageUpper, weightKG, filtered); + if (!lowerValues || !upperValues) return null; + + let ageRatio = ageUpper === ageLower ? 1 : (age - ageLower) / (ageUpper - ageLower); + ageRatio = Math.max(0, Math.min(1, ageRatio)); + + return interpolateStandardsValues(lowerValues, upperValues, ageRatio); +}; + +const interpolateByBodyWeight = ( + agePoint: number, + bodyWeightKG: number, + filtered: StandardsItem[], +): Levels | null => { + const ageFiltered = filtered.filter((item) => item.age === agePoint); + if (ageFiltered[0].bodyWeight === -1) return ageFiltered[0]; + + const weightArray = [...new Set(ageFiltered.map((obj) => obj.bodyWeight))].sort((a, b) => a - b); + const { lower, upper } = findNearestPoints(bodyWeightKG, weightArray); + + const weightLower = ageFiltered.find((i) => i.bodyWeight === lower); + const weightUpper = ageFiltered.find((i) => i.bodyWeight === upper); + if (!weightLower || !weightUpper) return null; + + let weightRatio = upper === lower ? 1 : (bodyWeightKG - lower) / (upper - lower); + weightRatio = Math.max(0, Math.min(1, weightRatio)); + + return interpolateStandardsValues(weightLower, weightUpper, weightRatio); +}; + +const interpolateStandardsValues = ( + lower: Levels, + upper: Levels, + ratio: number, +): Levels => { + const lerp = (k: keyof Levels): number => + (lower[k] as number) + ((upper[k] as number) - (lower[k] as number)) * ratio; + + return { + physicallyActive: lerp("physicallyActive"), + beginner: lerp("beginner"), + intermediate: lerp("intermediate"), + advanced: lerp("advanced"), + elite: lerp("elite"), + }; +}; diff --git a/api/calculator/data/standards.json b/api/calculator/data/standards.json new file mode 100644 index 0000000..56cd188 --- /dev/null +++ b/api/calculator/data/standards.json @@ -0,0 +1,5788 @@ +[ + { + "age": 17, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 34, + "beginner": 59, + "intermediate": 78, + "advanced": 107, + "elite": 136 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 38, + "beginner": 65, + "intermediate": 87, + "advanced": 120, + "elite": 158 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 46, + "beginner": 80, + "intermediate": 106, + "advanced": 146, + "elite": 192 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 49, + "beginner": 85, + "intermediate": 113, + "advanced": 155, + "elite": 205 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 52, + "beginner": 89, + "intermediate": 118, + "advanced": 162, + "elite": 209 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 53, + "beginner": 90, + "intermediate": 120, + "advanced": 165, + "elite": 213 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 56, + "beginner": 97, + "intermediate": 129, + "advanced": 177, + "elite": 219 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 38, + "beginner": 65, + "intermediate": 87, + "advanced": 120, + "elite": 153 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 46, + "beginner": 78, + "intermediate": 104, + "advanced": 143, + "elite": 189 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 51, + "beginner": 87, + "intermediate": 116, + "advanced": 160, + "elite": 210 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 58, + "beginner": 98, + "intermediate": 130, + "advanced": 179, + "elite": 236 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 57, + "beginner": 98, + "intermediate": 131, + "advanced": 180, + "elite": 232 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 70, + "beginner": 120, + "intermediate": 160, + "advanced": 220, + "elite": 285 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 68, + "beginner": 116, + "intermediate": 164, + "advanced": 226, + "elite": 282 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 40, + "beginner": 68, + "intermediate": 91, + "advanced": 125, + "elite": 159 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 48, + "beginner": 82, + "intermediate": 110, + "advanced": 151, + "elite": 199 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 53, + "beginner": 91, + "intermediate": 122, + "advanced": 167, + "elite": 220 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 58, + "beginner": 99, + "intermediate": 132, + "advanced": 181, + "elite": 238 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 62, + "beginner": 106, + "intermediate": 142, + "advanced": 195, + "elite": 252 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 66, + "beginner": 113, + "intermediate": 150, + "advanced": 206, + "elite": 267 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 74, + "beginner": 127, + "intermediate": 169, + "advanced": 232, + "elite": 291 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 38, + "beginner": 65, + "intermediate": 86, + "advanced": 118, + "elite": 142 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 43, + "beginner": 73, + "intermediate": 98, + "advanced": 134, + "elite": 161 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 46, + "beginner": 79, + "intermediate": 105, + "advanced": 144, + "elite": 173 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 54, + "beginner": 92, + "intermediate": 123, + "advanced": 169, + "elite": 203 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 56, + "beginner": 97, + "intermediate": 129, + "advanced": 177, + "elite": 213 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 61, + "beginner": 104, + "intermediate": 139, + "advanced": 191, + "elite": 229 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 66, + "beginner": 113, + "intermediate": 150, + "advanced": 206, + "elite": 248 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 32, + "beginner": 55, + "intermediate": 73, + "advanced": 100, + "elite": 132 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 37, + "beginner": 64, + "intermediate": 85, + "advanced": 117, + "elite": 154 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 42, + "beginner": 71, + "intermediate": 95, + "advanced": 131, + "elite": 172 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 46, + "beginner": 80, + "intermediate": 106, + "advanced": 146, + "elite": 192 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 50, + "beginner": 86, + "intermediate": 114, + "advanced": 157, + "elite": 207 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 53, + "beginner": 90, + "intermediate": 120, + "advanced": 165, + "elite": 218 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 54, + "beginner": 93, + "intermediate": 124, + "advanced": 171, + "elite": 225 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 23, + "beginner": 40, + "intermediate": 53, + "advanced": 73, + "elite": 96 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 33, + "beginner": 57, + "intermediate": 76, + "advanced": 105, + "elite": 138 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 40, + "beginner": 68, + "intermediate": 91, + "advanced": 125, + "elite": 165 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 43, + "beginner": 74, + "intermediate": 98, + "advanced": 135, + "elite": 178 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 47, + "beginner": 80, + "intermediate": 107, + "advanced": 147, + "elite": 194 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 48, + "beginner": 83, + "intermediate": 110, + "advanced": 151, + "elite": 199 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 50, + "beginner": 86, + "intermediate": 115, + "advanced": 158, + "elite": 208 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 22, + "beginner": 38, + "intermediate": 51, + "advanced": 70, + "elite": 92 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 30, + "beginner": 51, + "intermediate": 68, + "advanced": 94, + "elite": 123 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 33, + "beginner": 56, + "intermediate": 75, + "advanced": 103, + "elite": 136 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 34, + "beginner": 59, + "intermediate": 78, + "advanced": 107, + "elite": 141 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 35, + "beginner": 59, + "intermediate": 79, + "advanced": 109, + "elite": 143 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 35, + "beginner": 60, + "intermediate": 80, + "advanced": 110, + "elite": 145 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 36, + "beginner": 62, + "intermediate": 82, + "advanced": 113, + "elite": 149 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 18, + "beginner": 30, + "intermediate": 40, + "advanced": 55, + "elite": 73 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 24, + "beginner": 40, + "intermediate": 54, + "advanced": 74, + "elite": 97 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 26, + "beginner": 44, + "intermediate": 59, + "advanced": 81, + "elite": 107 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 27, + "beginner": 46, + "intermediate": 62, + "advanced": 85, + "elite": 112 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 28, + "beginner": 46, + "intermediate": 62, + "advanced": 86, + "elite": 113 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 28, + "beginner": 47, + "intermediate": 63, + "advanced": 87, + "elite": 115 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 28, + "beginner": 49, + "intermediate": 65, + "advanced": 89, + "elite": 117 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 23, + "beginner": 32, + "intermediate": 44, + "advanced": 61, + "elite": 84 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 29, + "beginner": 41, + "intermediate": 56, + "advanced": 77, + "elite": 106 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 32, + "beginner": 44, + "intermediate": 61, + "advanced": 84, + "elite": 116 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 35, + "beginner": 48, + "intermediate": 66, + "advanced": 91, + "elite": 126 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 35, + "beginner": 48, + "intermediate": 66, + "advanced": 91, + "elite": 125 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 36, + "beginner": 50, + "intermediate": 68, + "advanced": 94, + "elite": 130 + }, + { + "age": 17, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 53, + "beginner": 73, + "intermediate": 100, + "advanced": 138, + "elite": 190 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 27, + "beginner": 37, + "intermediate": 51, + "advanced": 70, + "elite": 97 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 32, + "beginner": 45, + "intermediate": 61, + "advanced": 85, + "elite": 118 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 35, + "beginner": 49, + "intermediate": 67, + "advanced": 93, + "elite": 128 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 36, + "beginner": 50, + "intermediate": 69, + "advanced": 95, + "elite": 132 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 40, + "beginner": 55, + "intermediate": 76, + "advanced": 105, + "elite": 145 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 46, + "beginner": 63, + "intermediate": 87, + "advanced": 120, + "elite": 165 + }, + { + "age": 25, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 57, + "beginner": 75, + "intermediate": 105, + "advanced": 140, + "elite": 195 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 28, + "beginner": 43, + "intermediate": 65, + "advanced": 89, + "elite": 112 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 34, + "beginner": 48, + "intermediate": 71, + "advanced": 97, + "elite": 128 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 36, + "beginner": 55, + "intermediate": 80, + "advanced": 110, + "elite": 144 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 38, + "beginner": 59, + "intermediate": 85, + "advanced": 117, + "elite": 154 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 44, + "beginner": 62, + "intermediate": 89, + "advanced": 123, + "elite": 157 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 51, + "beginner": 68, + "intermediate": 97, + "advanced": 134, + "elite": 171 + }, + { + "age": 35, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 60, + "beginner": 81, + "intermediate": 114, + "advanced": 157, + "elite": 192 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 23, + "beginner": 38, + "intermediate": 41, + "advanced": 69, + "elite": 78 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 30, + "beginner": 49, + "intermediate": 55, + "advanced": 90, + "elite": 100 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 33, + "beginner": 53, + "intermediate": 59, + "advanced": 96, + "elite": 108 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 34, + "beginner": 55, + "intermediate": 62, + "advanced": 101, + "elite": 114 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 36, + "beginner": 58, + "intermediate": 65, + "advanced": 105, + "elite": 119 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 38, + "beginner": 61, + "intermediate": 69, + "advanced": 111, + "elite": 126 + }, + { + "age": 45, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 40, + "beginner": 64, + "intermediate": 73, + "advanced": 117, + "elite": 133 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 19, + "beginner": 33, + "intermediate": 40, + "advanced": 60, + "elite": 76 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 24, + "beginner": 41, + "intermediate": 54, + "advanced": 74, + "elite": 97 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 25, + "beginner": 42, + "intermediate": 56, + "advanced": 76, + "elite": 102 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 26, + "beginner": 44, + "intermediate": 59, + "advanced": 81, + "elite": 107 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 29, + "beginner": 49, + "intermediate": 64, + "advanced": 90, + "elite": 118 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 29, + "beginner": 50, + "intermediate": 67, + "advanced": 92, + "elite": 121 + }, + { + "age": 55, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 35, + "beginner": 59, + "intermediate": 70, + "advanced": 111, + "elite": 130 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 15, + "beginner": 26, + "intermediate": 35, + "advanced": 48, + "elite": 63 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 18, + "beginner": 33, + "intermediate": 44, + "advanced": 62, + "elite": 81 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 20, + "beginner": 35, + "intermediate": 47, + "advanced": 65, + "elite": 83 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 22, + "beginner": 37, + "intermediate": 48, + "advanced": 66, + "elite": 85 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 24, + "beginner": 40, + "intermediate": 54, + "advanced": 74, + "elite": 93 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 25, + "beginner": 42, + "intermediate": 56, + "advanced": 78, + "elite": 99 + }, + { + "age": 65, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 26, + "beginner": 45, + "intermediate": 58, + "advanced": 79, + "elite": 102 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 14, + "beginner": 24, + "intermediate": 32, + "advanced": 44, + "elite": 58 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 15, + "beginner": 25, + "intermediate": 33, + "advanced": 46, + "elite": 60 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 16, + "beginner": 27, + "intermediate": 36, + "advanced": 50, + "elite": 65 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 17, + "beginner": 28, + "intermediate": 37, + "advanced": 52, + "elite": 69 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 17, + "beginner": 29, + "intermediate": 39, + "advanced": 54, + "elite": 71 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 18, + "beginner": 30, + "intermediate": 40, + "advanced": 55, + "elite": 73 + }, + { + "age": 75, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 18, + "beginner": 30, + "intermediate": 40, + "advanced": 55, + "elite": 73 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 11, + "beginner": 19, + "intermediate": 25, + "advanced": 35, + "elite": 46 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 11, + "beginner": 20, + "intermediate": 26, + "advanced": 36, + "elite": 48 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 12, + "beginner": 21, + "intermediate": 28, + "advanced": 39, + "elite": 52 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 13, + "beginner": 23, + "intermediate": 30, + "advanced": 41, + "elite": 54 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 13, + "beginner": 23, + "intermediate": 31, + "advanced": 42, + "elite": 56 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 14, + "beginner": 24, + "intermediate": 32, + "advanced": 43, + "elite": 57 + }, + { + "age": 85, + "activityType": "Back Squat", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 14, + "beginner": 24, + "intermediate": 32, + "advanced": 43, + "elite": 57 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 34, + "beginner": 47, + "intermediate": 61, + "advanced": 74, + "elite": 85 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 42, + "beginner": 59, + "intermediate": 76, + "advanced": 92, + "elite": 107 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 43, + "beginner": 60, + "intermediate": 77, + "advanced": 94, + "elite": 110 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 51, + "beginner": 71, + "intermediate": 91, + "advanced": 111, + "elite": 132 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 53, + "beginner": 74, + "intermediate": 95, + "advanced": 116, + "elite": 134 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 53, + "beginner": 74, + "intermediate": 96, + "advanced": 117, + "elite": 137 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 53, + "beginner": 74, + "intermediate": 95, + "advanced": 116, + "elite": 138 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 36, + "beginner": 51, + "intermediate": 65, + "advanced": 80, + "elite": 92 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 50, + "beginner": 70, + "intermediate": 90, + "advanced": 110, + "elite": 130 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 50, + "beginner": 70, + "intermediate": 90, + "advanced": 110, + "elite": 150 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 52, + "beginner": 73, + "intermediate": 93, + "advanced": 114, + "elite": 161 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 55, + "beginner": 77, + "intermediate": 99, + "advanced": 121, + "elite": 170 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 59, + "beginner": 82, + "intermediate": 106, + "advanced": 129, + "elite": 181 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 61, + "beginner": 85, + "intermediate": 109, + "advanced": 133, + "elite": 182 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 39, + "beginner": 55, + "intermediate": 71, + "advanced": 87, + "elite": 114 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 53, + "beginner": 75, + "intermediate": 96, + "advanced": 117, + "elite": 155 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 54, + "beginner": 75, + "intermediate": 97, + "advanced": 119, + "elite": 156 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 59, + "beginner": 83, + "intermediate": 107, + "advanced": 131, + "elite": 173 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 61, + "beginner": 84, + "intermediate": 108, + "advanced": 135, + "elite": 176 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 62, + "beginner": 85, + "intermediate": 110, + "advanced": 139, + "elite": 177 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 67, + "beginner": 94, + "intermediate": 121, + "advanced": 148, + "elite": 195 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 37, + "beginner": 52, + "intermediate": 66, + "advanced": 81, + "elite": 105 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 41, + "beginner": 57, + "intermediate": 73, + "advanced": 89, + "elite": 116 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 48, + "beginner": 67, + "intermediate": 86, + "advanced": 105, + "elite": 135 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 54, + "beginner": 75, + "intermediate": 97, + "advanced": 118, + "elite": 143 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 56, + "beginner": 78, + "intermediate": 100, + "advanced": 122, + "elite": 154 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 58, + "beginner": 81, + "intermediate": 104, + "advanced": 127, + "elite": 164 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 62, + "beginner": 87, + "intermediate": 111, + "advanced": 136, + "elite": 166 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 29, + "beginner": 41, + "intermediate": 53, + "advanced": 65, + "elite": 74 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 40, + "beginner": 56, + "intermediate": 72, + "advanced": 88, + "elite": 104 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 43, + "beginner": 60, + "intermediate": 77, + "advanced": 94, + "elite": 111 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 49, + "beginner": 68, + "intermediate": 88, + "advanced": 107, + "elite": 129 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 53, + "beginner": 74, + "intermediate": 95, + "advanced": 116, + "elite": 140 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 54, + "beginner": 75, + "intermediate": 97, + "advanced": 118, + "elite": 143 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 54, + "beginner": 76, + "intermediate": 98, + "advanced": 120, + "elite": 145 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 25, + "beginner": 35, + "intermediate": 45, + "advanced": 55, + "elite": 68 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 32, + "beginner": 45, + "intermediate": 57, + "advanced": 70, + "elite": 88 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 36, + "beginner": 50, + "intermediate": 64, + "advanced": 78, + "elite": 99 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 47, + "beginner": 66, + "intermediate": 84, + "advanced": 103, + "elite": 131 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 48, + "beginner": 67, + "intermediate": 87, + "advanced": 106, + "elite": 134 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 49, + "beginner": 68, + "intermediate": 88, + "advanced": 107, + "elite": 136 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 50, + "beginner": 69, + "intermediate": 89, + "advanced": 109, + "elite": 138 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 23, + "beginner": 32, + "intermediate": 41, + "advanced": 50, + "elite": 60 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 29, + "beginner": 40, + "intermediate": 52, + "advanced": 63, + "elite": 78 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 33, + "beginner": 46, + "intermediate": 59, + "advanced": 72, + "elite": 89 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 34, + "beginner": 48, + "intermediate": 62, + "advanced": 76, + "elite": 94 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 36, + "beginner": 51, + "intermediate": 65, + "advanced": 80, + "elite": 99 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 44, + "beginner": 61, + "intermediate": 79, + "advanced": 96, + "elite": 121 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 48, + "beginner": 67, + "intermediate": 86, + "advanced": 105, + "elite": 131 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 16, + "beginner": 22, + "intermediate": 28, + "advanced": 34, + "elite": 41 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 20, + "beginner": 28, + "intermediate": 36, + "advanced": 44, + "elite": 54 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 22, + "beginner": 31, + "intermediate": 40, + "advanced": 49, + "elite": 61 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 24, + "beginner": 33, + "intermediate": 43, + "advanced": 52, + "elite": 65 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 25, + "beginner": 35, + "intermediate": 45, + "advanced": 55, + "elite": 69 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 30, + "beginner": 42, + "intermediate": 54, + "advanced": 66, + "elite": 83 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 33, + "beginner": 46, + "intermediate": 59, + "advanced": 72, + "elite": 91 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 14, + "beginner": 19, + "intermediate": 27, + "advanced": 37, + "elite": 51 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 17, + "beginner": 23, + "intermediate": 32, + "advanced": 44, + "elite": 61 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 19, + "beginner": 27, + "intermediate": 37, + "advanced": 51, + "elite": 70 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 21, + "beginner": 28, + "intermediate": 39, + "advanced": 54, + "elite": 75 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 22, + "beginner": 30, + "intermediate": 41, + "advanced": 57, + "elite": 78 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 22, + "beginner": 31, + "intermediate": 42, + "advanced": 58, + "elite": 81 + }, + { + "age": 17, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 23, + "beginner": 32, + "intermediate": 44, + "advanced": 61, + "elite": 84 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 14, + "beginner": 19, + "intermediate": 26, + "advanced": 36, + "elite": 49 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 19, + "beginner": 27, + "intermediate": 37, + "advanced": 51, + "elite": 70 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 21, + "beginner": 29, + "intermediate": 40, + "advanced": 56, + "elite": 77 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 22, + "beginner": 30, + "intermediate": 42, + "advanced": 57, + "elite": 79 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 25, + "beginner": 34, + "intermediate": 47, + "advanced": 64, + "elite": 89 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 25, + "beginner": 35, + "intermediate": 48, + "advanced": 66, + "elite": 91 + }, + { + "age": 25, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 28, + "beginner": 39, + "intermediate": 54, + "advanced": 75, + "elite": 103 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 12, + "beginner": 17, + "intermediate": 22, + "advanced": 27, + "elite": 57 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 30, + "beginner": 41, + "intermediate": 53, + "advanced": 65, + "elite": 83 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 33, + "beginner": 45, + "intermediate": 60, + "advanced": 73, + "elite": 89 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 35, + "beginner": 51, + "intermediate": 66, + "advanced": 80, + "elite": 98 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 38, + "beginner": 51, + "intermediate": 67, + "advanced": 84, + "elite": 100 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 39, + "beginner": 52, + "intermediate": 66, + "advanced": 86, + "elite": 102 + }, + { + "age": 35, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 41, + "beginner": 58, + "intermediate": 74, + "advanced": 90, + "elite": 106 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 14, + "beginner": 14, + "intermediate": 25, + "advanced": 25, + "elite": 46 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 20, + "beginner": 31, + "intermediate": 36, + "advanced": 56, + "elite": 66 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 23, + "beginner": 37, + "intermediate": 41, + "advanced": 67, + "elite": 75 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 24, + "beginner": 44, + "intermediate": 44, + "advanced": 80, + "elite": 81 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 26, + "beginner": 32, + "intermediate": 44, + "advanced": 59, + "elite": 85 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 26, + "beginner": 41, + "intermediate": 48, + "advanced": 75, + "elite": 87 + }, + { + "age": 45, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 28, + "beginner": 44, + "intermediate": 51, + "advanced": 79, + "elite": 93 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 7, + "beginner": 13, + "intermediate": 17, + "advanced": 23, + "elite": 43 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 16, + "beginner": 22, + "intermediate": 32, + "advanced": 37, + "elite": 61 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 18, + "beginner": 30, + "intermediate": 40, + "advanced": 55, + "elite": 68 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 18, + "beginner": 31, + "intermediate": 41, + "advanced": 56, + "elite": 69 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 15, + "beginner": 27, + "intermediate": 35, + "advanced": 49, + "elite": 72 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 18, + "beginner": 32, + "intermediate": 42, + "advanced": 58, + "elite": 75 + }, + { + "age": 55, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 21, + "beginner": 36, + "intermediate": 48, + "advanced": 66, + "elite": 82 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 9, + "beginner": 13, + "intermediate": 17, + "advanced": 38, + "elite": 38 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 18, + "beginner": 33, + "intermediate": 44, + "advanced": 40, + "elite": 53 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 20, + "beginner": 25, + "intermediate": 34, + "advanced": 46, + "elite": 61 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 22, + "beginner": 33, + "intermediate": 48, + "advanced": 66, + "elite": 62 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 12, + "beginner": 20, + "intermediate": 27, + "advanced": 37, + "elite": 65 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 18, + "beginner": 31, + "intermediate": 41, + "advanced": 56, + "elite": 69 + }, + { + "age": 65, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 20, + "beginner": 45, + "intermediate": 58, + "advanced": 65, + "elite": 70 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 9, + "beginner": 12, + "intermediate": 16, + "advanced": 21, + "elite": 28 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 14, + "beginner": 18, + "intermediate": 24, + "advanced": 32, + "elite": 43 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 16, + "beginner": 21, + "intermediate": 28, + "advanced": 37, + "elite": 49 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 17, + "beginner": 23, + "intermediate": 30, + "advanced": 40, + "elite": 54 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 17, + "beginner": 23, + "intermediate": 31, + "advanced": 41, + "elite": 55 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 18, + "beginner": 24, + "intermediate": 32, + "advanced": 42, + "elite": 56 + }, + { + "age": 75, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 19, + "beginner": 25, + "intermediate": 33, + "advanced": 44, + "elite": 59 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 8, + "beginner": 10, + "intermediate": 14, + "advanced": 18, + "elite": 24 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 9, + "beginner": 14, + "intermediate": 19, + "advanced": 25, + "elite": 34 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 12, + "beginner": 16, + "intermediate": 22, + "advanced": 29, + "elite": 39 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 13, + "beginner": 18, + "intermediate": 24, + "advanced": 32, + "elite": 43 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 14, + "beginner": 19, + "intermediate": 25, + "advanced": 33, + "elite": 44 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 15, + "beginner": 19, + "intermediate": 26, + "advanced": 34, + "elite": 46 + }, + { + "age": 85, + "activityType": "Bench Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 15, + "beginner": 20, + "intermediate": 27, + "advanced": 36, + "elite": 48 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 45, + "beginner": 74, + "intermediate": 93, + "advanced": 103, + "elite": 115 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 58, + "beginner": 97, + "intermediate": 121, + "advanced": 134, + "elite": 149 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 73, + "beginner": 122, + "intermediate": 152, + "advanced": 169, + "elite": 188 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 77, + "beginner": 129, + "intermediate": 161, + "advanced": 179, + "elite": 199 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 81, + "beginner": 135, + "intermediate": 169, + "advanced": 188, + "elite": 209 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 82, + "beginner": 137, + "intermediate": 172, + "advanced": 191, + "elite": 212 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 84, + "beginner": 139, + "intermediate": 174, + "advanced": 194, + "elite": 215 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 47, + "beginner": 81, + "intermediate": 101, + "advanced": 127, + "elite": 141 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 64, + "beginner": 112, + "intermediate": 139, + "advanced": 186, + "elite": 207 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 76, + "beginner": 131, + "intermediate": 164, + "advanced": 219, + "elite": 243 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 83, + "beginner": 144, + "intermediate": 180, + "advanced": 240, + "elite": 266 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 84, + "beginner": 146, + "intermediate": 182, + "advanced": 243, + "elite": 270 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 85, + "beginner": 147, + "intermediate": 184, + "advanced": 245, + "elite": 273 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 86, + "beginner": 149, + "intermediate": 187, + "advanced": 249, + "elite": 276 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 51, + "beginner": 89, + "intermediate": 112, + "advanced": 149, + "elite": 175 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 64, + "beginner": 112, + "intermediate": 140, + "advanced": 186, + "elite": 219 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 76, + "beginner": 132, + "intermediate": 165, + "advanced": 220, + "elite": 259 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 81, + "beginner": 142, + "intermediate": 177, + "advanced": 236, + "elite": 278 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 83, + "beginner": 145, + "intermediate": 181, + "advanced": 242, + "elite": 284 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 84, + "beginner": 146, + "intermediate": 183, + "advanced": 244, + "elite": 287 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 89, + "beginner": 154, + "intermediate": 192, + "advanced": 257, + "elite": 302 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 46, + "beginner": 80, + "intermediate": 100, + "advanced": 118, + "elite": 131 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 53, + "beginner": 92, + "intermediate": 115, + "advanced": 154, + "elite": 181 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 63, + "beginner": 109, + "intermediate": 137, + "advanced": 182, + "elite": 214 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 65, + "beginner": 113, + "intermediate": 141, + "advanced": 188, + "elite": 222 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 71, + "beginner": 124, + "intermediate": 154, + "advanced": 206, + "elite": 242 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 75, + "beginner": 130, + "intermediate": 162, + "advanced": 217, + "elite": 255 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 76, + "beginner": 133, + "intermediate": 166, + "advanced": 221, + "elite": 260 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 40, + "beginner": 69, + "intermediate": 86, + "advanced": 102, + "elite": 113 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 48, + "beginner": 84, + "intermediate": 105, + "advanced": 140, + "elite": 164 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 56, + "beginner": 97, + "intermediate": 121, + "advanced": 161, + "elite": 190 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 60, + "beginner": 104, + "intermediate": 130, + "advanced": 173, + "elite": 204 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 63, + "beginner": 110, + "intermediate": 138, + "advanced": 183, + "elite": 216 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 64, + "beginner": 111, + "intermediate": 139, + "advanced": 185, + "elite": 218 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 65, + "beginner": 114, + "intermediate": 142, + "advanced": 190, + "elite": 223 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 35, + "beginner": 61, + "intermediate": 79, + "advanced": 95, + "elite": 109 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 46, + "beginner": 79, + "intermediate": 103, + "advanced": 124, + "elite": 142 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 52, + "beginner": 90, + "intermediate": 117, + "advanced": 141, + "elite": 162 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 57, + "beginner": 98, + "intermediate": 128, + "advanced": 155, + "elite": 177 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 61, + "beginner": 107, + "intermediate": 138, + "advanced": 167, + "elite": 191 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 62, + "beginner": 109, + "intermediate": 140, + "advanced": 170, + "elite": 194 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 64, + "beginner": 112, + "intermediate": 144, + "advanced": 175, + "elite": 200 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 29, + "beginner": 51, + "intermediate": 68, + "advanced": 85, + "elite": 98 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 36, + "beginner": 62, + "intermediate": 82, + "advanced": 103, + "elite": 121 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 42, + "beginner": 74, + "intermediate": 98, + "advanced": 123, + "elite": 144 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 45, + "beginner": 79, + "intermediate": 105, + "advanced": 131, + "elite": 155 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 49, + "beginner": 86, + "intermediate": 114, + "advanced": 143, + "elite": 168 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 50, + "beginner": 87, + "intermediate": 116, + "advanced": 145, + "elite": 170 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 52, + "beginner": 90, + "intermediate": 120, + "advanced": 150, + "elite": 176 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 21, + "beginner": 36, + "intermediate": 48, + "advanced": 60, + "elite": 68 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 25, + "beginner": 43, + "intermediate": 58, + "advanced": 72, + "elite": 85 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 30, + "beginner": 51, + "intermediate": 69, + "advanced": 86, + "elite": 101 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 32, + "beginner": 55, + "intermediate": 74, + "advanced": 92, + "elite": 108 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 35, + "beginner": 60, + "intermediate": 80, + "advanced": 100, + "elite": 118 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 35, + "beginner": 61, + "intermediate": 81, + "advanced": 101, + "elite": 119 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 36, + "beginner": 63, + "intermediate": 84, + "advanced": 105, + "elite": 123 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 17, + "beginner": 39, + "intermediate": 51, + "advanced": 62, + "elite": 82 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 22, + "beginner": 51, + "intermediate": 65, + "advanced": 80, + "elite": 102 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 24, + "beginner": 56, + "intermediate": 72, + "advanced": 88, + "elite": 108 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 25, + "beginner": 59, + "intermediate": 75, + "advanced": 92, + "elite": 113 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 26, + "beginner": 61, + "intermediate": 79, + "advanced": 99, + "elite": 118 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 27, + "beginner": 62, + "intermediate": 80, + "advanced": 103, + "elite": 123 + }, + { + "age": 17, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 29, + "beginner": 69, + "intermediate": 89, + "advanced": 109, + "elite": 129 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 25, + "beginner": 58, + "intermediate": 74, + "advanced": 91, + "elite": 120 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 30, + "beginner": 70, + "intermediate": 90, + "advanced": 110, + "elite": 140 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 33, + "beginner": 77, + "intermediate": 99, + "advanced": 121, + "elite": 150 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 34, + "beginner": 79, + "intermediate": 101, + "advanced": 124, + "elite": 154 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 35, + "beginner": 82, + "intermediate": 107, + "advanced": 133, + "elite": 162 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 35, + "beginner": 82, + "intermediate": 106, + "advanced": 134, + "elite": 164 + }, + { + "age": 25, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 36, + "beginner": 84, + "intermediate": 108, + "advanced": 132, + "elite": 159 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 30, + "beginner": 70, + "intermediate": 90, + "advanced": 110, + "elite": 145 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 32, + "beginner": 74, + "intermediate": 96, + "advanced": 117, + "elite": 149 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 35, + "beginner": 81, + "intermediate": 104, + "advanced": 127, + "elite": 157 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 36, + "beginner": 83, + "intermediate": 107, + "advanced": 131, + "elite": 162 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 39, + "beginner": 91, + "intermediate": 118, + "advanced": 147, + "elite": 179 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 40, + "beginner": 93, + "intermediate": 119, + "advanced": 151, + "elite": 185 + }, + { + "age": 35, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 40, + "beginner": 94, + "intermediate": 120, + "advanced": 147, + "elite": 178 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 23, + "beginner": 54, + "intermediate": 70, + "advanced": 85, + "elite": 112 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 29, + "beginner": 67, + "intermediate": 86, + "advanced": 105, + "elite": 133 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 30, + "beginner": 69, + "intermediate": 89, + "advanced": 109, + "elite": 134 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 32, + "beginner": 74, + "intermediate": 95, + "advanced": 116, + "elite": 143 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 33, + "beginner": 78, + "intermediate": 101, + "advanced": 126, + "elite": 153 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 35, + "beginner": 81, + "intermediate": 104, + "advanced": 132, + "elite": 160 + }, + { + "age": 45, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 35, + "beginner": 82, + "intermediate": 106, + "advanced": 129, + "elite": 156 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 22, + "beginner": 51, + "intermediate": 65, + "advanced": 80, + "elite": 105 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 24, + "beginner": 57, + "intermediate": 73, + "advanced": 89, + "elite": 114 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 26, + "beginner": 60, + "intermediate": 78, + "advanced": 95, + "elite": 117 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 28, + "beginner": 65, + "intermediate": 83, + "advanced": 102, + "elite": 126 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 29, + "beginner": 69, + "intermediate": 90, + "advanced": 112, + "elite": 136 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 30, + "beginner": 69, + "intermediate": 89, + "advanced": 114, + "elite": 137 + }, + { + "age": 55, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 31, + "beginner": 72, + "intermediate": 92, + "advanced": 113, + "elite": 135 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 18, + "beginner": 43, + "intermediate": 55, + "advanced": 67, + "elite": 89 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 23, + "beginner": 53, + "intermediate": 69, + "advanced": 84, + "elite": 107 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 24, + "beginner": 56, + "intermediate": 72, + "advanced": 89, + "elite": 109 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 25, + "beginner": 58, + "intermediate": 74, + "advanced": 91, + "elite": 112 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 25, + "beginner": 60, + "intermediate": 77, + "advanced": 97, + "elite": 116 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 26, + "beginner": 60, + "intermediate": 77, + "advanced": 99, + "elite": 118 + }, + { + "age": 65, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 26, + "beginner": 60, + "intermediate": 78, + "advanced": 95, + "elite": 112 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 18, + "beginner": 42, + "intermediate": 53, + "advanced": 66, + "elite": 84 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 18, + "beginner": 43, + "intermediate": 55, + "advanced": 67, + "elite": 86 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 20, + "beginner": 46, + "intermediate": 59, + "advanced": 72, + "elite": 92 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 20, + "beginner": 47, + "intermediate": 60, + "advanced": 73, + "elite": 93 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 20, + "beginner": 47, + "intermediate": 61, + "advanced": 79, + "elite": 94 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 20, + "beginner": 47, + "intermediate": 61, + "advanced": 79, + "elite": 95 + }, + { + "age": 75, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 20, + "beginner": 48, + "intermediate": 61, + "advanced": 79, + "elite": 95 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 15, + "beginner": 34, + "intermediate": 44, + "advanced": 53, + "elite": 68 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 15, + "beginner": 35, + "intermediate": 45, + "advanced": 55, + "elite": 69 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 16, + "beginner": 37, + "intermediate": 48, + "advanced": 58, + "elite": 74 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 16, + "beginner": 38, + "intermediate": 48, + "advanced": 59, + "elite": 75 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 16, + "beginner": 38, + "intermediate": 50, + "advanced": 65, + "elite": 76 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 16, + "beginner": 38, + "intermediate": 49, + "advanced": 65, + "elite": 77 + }, + { + "age": 85, + "activityType": "Deadlift", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 17, + "beginner": 39, + "intermediate": 50, + "advanced": 65, + "elite": 77 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 18, + "beginner": 26, + "intermediate": 33, + "advanced": 41, + "elite": 53 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 22, + "beginner": 31, + "intermediate": 40, + "advanced": 49, + "elite": 64 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 24, + "beginner": 34, + "intermediate": 44, + "advanced": 54, + "elite": 70 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 28, + "beginner": 39, + "intermediate": 50, + "advanced": 61, + "elite": 80 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 29, + "beginner": 40, + "intermediate": 51, + "advanced": 63, + "elite": 83 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 29, + "beginner": 41, + "intermediate": 53, + "advanced": 65, + "elite": 85 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 31, + "beginner": 43, + "intermediate": 56, + "advanced": 69, + "elite": 90 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 23, + "beginner": 32, + "intermediate": 42, + "advanced": 51, + "elite": 67 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 28, + "beginner": 39, + "intermediate": 51, + "advanced": 62, + "elite": 82 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 31, + "beginner": 43, + "intermediate": 55, + "advanced": 68, + "elite": 89 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 35, + "beginner": 49, + "intermediate": 63, + "advanced": 78, + "elite": 102 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 36, + "beginner": 50, + "intermediate": 65, + "advanced": 80, + "elite": 105 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 37, + "beginner": 52, + "intermediate": 67, + "advanced": 82, + "elite": 108 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 39, + "beginner": 55, + "intermediate": 70, + "advanced": 87, + "elite": 114 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 25, + "beginner": 35, + "intermediate": 45, + "advanced": 55, + "elite": 72 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 30, + "beginner": 42, + "intermediate": 54, + "advanced": 67, + "elite": 88 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 33, + "beginner": 46, + "intermediate": 59, + "advanced": 73, + "elite": 96 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 38, + "beginner": 53, + "intermediate": 68, + "advanced": 84, + "elite": 109 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 39, + "beginner": 54, + "intermediate": 70, + "advanced": 86, + "elite": 112 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 40, + "beginner": 56, + "intermediate": 72, + "advanced": 89, + "elite": 116 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 42, + "beginner": 59, + "intermediate": 76, + "advanced": 93, + "elite": 122 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 21, + "beginner": 30, + "intermediate": 38, + "advanced": 47, + "elite": 62 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 26, + "beginner": 36, + "intermediate": 47, + "advanced": 58, + "elite": 75 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 28, + "beginner": 40, + "intermediate": 51, + "advanced": 63, + "elite": 82 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 32, + "beginner": 45, + "intermediate": 58, + "advanced": 72, + "elite": 94 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 33, + "beginner": 47, + "intermediate": 60, + "advanced": 74, + "elite": 97 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 34, + "beginner": 48, + "intermediate": 62, + "advanced": 76, + "elite": 100 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 36, + "beginner": 51, + "intermediate": 65, + "advanced": 80, + "elite": 105 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 18, + "beginner": 26, + "intermediate": 33, + "advanced": 41, + "elite": 53 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 22, + "beginner": 31, + "intermediate": 40, + "advanced": 50, + "elite": 65 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 24, + "beginner": 34, + "intermediate": 44, + "advanced": 54, + "elite": 71 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 28, + "beginner": 39, + "intermediate": 50, + "advanced": 62, + "elite": 81 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 29, + "beginner": 40, + "intermediate": 51, + "advanced": 63, + "elite": 83 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 30, + "beginner": 41, + "intermediate": 53, + "advanced": 65, + "elite": 86 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 31, + "beginner": 44, + "intermediate": 56, + "advanced": 69, + "elite": 90 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 17, + "beginner": 24, + "intermediate": 31, + "advanced": 38, + "elite": 50 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 21, + "beginner": 29, + "intermediate": 38, + "advanced": 46, + "elite": 61 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 23, + "beginner": 32, + "intermediate": 41, + "advanced": 51, + "elite": 66 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 26, + "beginner": 36, + "intermediate": 47, + "advanced": 58, + "elite": 76 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 27, + "beginner": 38, + "intermediate": 48, + "advanced": 60, + "elite": 78 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 28, + "beginner": 39, + "intermediate": 50, + "advanced": 61, + "elite": 80 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 29, + "beginner": 41, + "intermediate": 53, + "advanced": 65, + "elite": 85 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 15, + "beginner": 20, + "intermediate": 26, + "advanced": 32, + "elite": 42 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 18, + "beginner": 25, + "intermediate": 32, + "advanced": 39, + "elite": 51 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 19, + "beginner": 27, + "intermediate": 35, + "advanced": 43, + "elite": 56 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 22, + "beginner": 31, + "intermediate": 40, + "advanced": 49, + "elite": 64 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 23, + "beginner": 32, + "intermediate": 41, + "advanced": 50, + "elite": 66 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 24, + "beginner": 33, + "intermediate": 42, + "advanced": 52, + "elite": 68 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 25, + "beginner": 35, + "intermediate": 44, + "advanced": 55, + "elite": 72 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 57, + "physicallyActive": 10, + "beginner": 14, + "intermediate": 18, + "advanced": 22, + "elite": 29 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 68, + "physicallyActive": 12, + "beginner": 17, + "intermediate": 22, + "advanced": 27, + "elite": 36 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 79, + "physicallyActive": 13, + "beginner": 19, + "intermediate": 24, + "advanced": 30, + "elite": 39 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 91, + "physicallyActive": 15, + "beginner": 21, + "intermediate": 27, + "advanced": 34, + "elite": 44 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 102, + "physicallyActive": 16, + "beginner": 22, + "intermediate": 28, + "advanced": 35, + "elite": 46 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 113, + "physicallyActive": 16, + "beginner": 23, + "intermediate": 29, + "advanced": 36, + "elite": 47 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "male", + "bodyWeight": 136, + "physicallyActive": 17, + "beginner": 24, + "intermediate": 31, + "advanced": 38, + "elite": 50 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 11, + "beginner": 14, + "intermediate": 18, + "advanced": 23, + "elite": 31 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 13, + "beginner": 17, + "intermediate": 20, + "advanced": 27, + "elite": 37 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 14, + "beginner": 18, + "intermediate": 22, + "advanced": 29, + "elite": 40 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 15, + "beginner": 21, + "intermediate": 24, + "advanced": 32, + "elite": 43 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 16, + "beginner": 22, + "intermediate": 26, + "advanced": 35, + "elite": 46 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 17, + "beginner": 24, + "intermediate": 28, + "advanced": 37, + "elite": 48 + }, + { + "age": 17, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 19, + "beginner": 27, + "intermediate": 31, + "advanced": 41, + "elite": 52 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 14, + "beginner": 18, + "intermediate": 22, + "advanced": 29, + "elite": 39 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 16, + "beginner": 21, + "intermediate": 26, + "advanced": 34, + "elite": 47 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 18, + "beginner": 23, + "intermediate": 28, + "advanced": 37, + "elite": 50 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 19, + "beginner": 26, + "intermediate": 31, + "advanced": 40, + "elite": 54 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 20, + "beginner": 28, + "intermediate": 33, + "advanced": 45, + "elite": 59 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 21, + "beginner": 31, + "intermediate": 35, + "advanced": 47, + "elite": 60 + }, + { + "age": 25, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 25, + "beginner": 34, + "intermediate": 39, + "advanced": 52, + "elite": 66 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 15, + "beginner": 19, + "intermediate": 24, + "advanced": 32, + "elite": 42 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 18, + "beginner": 23, + "intermediate": 28, + "advanced": 37, + "elite": 50 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 19, + "beginner": 25, + "intermediate": 30, + "advanced": 40, + "elite": 54 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 20, + "beginner": 28, + "intermediate": 33, + "advanced": 43, + "elite": 58 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 22, + "beginner": 30, + "intermediate": 35, + "advanced": 48, + "elite": 63 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 23, + "beginner": 33, + "intermediate": 38, + "advanced": 50, + "elite": 65 + }, + { + "age": 35, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 27, + "beginner": 37, + "intermediate": 42, + "advanced": 56, + "elite": 71 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 13, + "beginner": 16, + "intermediate": 21, + "advanced": 27, + "elite": 36 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 15, + "beginner": 19, + "intermediate": 24, + "advanced": 31, + "elite": 43 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 16, + "beginner": 21, + "intermediate": 26, + "advanced": 34, + "elite": 46 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 17, + "beginner": 24, + "intermediate": 28, + "advanced": 37, + "elite": 50 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 19, + "beginner": 26, + "intermediate": 30, + "advanced": 41, + "elite": 54 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 20, + "beginner": 28, + "intermediate": 33, + "advanced": 43, + "elite": 56 + }, + { + "age": 45, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 23, + "beginner": 31, + "intermediate": 36, + "advanced": 48, + "elite": 61 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 11, + "beginner": 14, + "intermediate": 18, + "advanced": 23, + "elite": 31 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 13, + "beginner": 17, + "intermediate": 20, + "advanced": 27, + "elite": 37 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 14, + "beginner": 18, + "intermediate": 22, + "advanced": 30, + "elite": 40 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 15, + "beginner": 21, + "intermediate": 24, + "advanced": 32, + "elite": 43 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 16, + "beginner": 22, + "intermediate": 26, + "advanced": 35, + "elite": 47 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 17, + "beginner": 24, + "intermediate": 28, + "advanced": 37, + "elite": 48 + }, + { + "age": 55, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 20, + "beginner": 27, + "intermediate": 31, + "advanced": 41, + "elite": 52 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 11, + "beginner": 13, + "intermediate": 17, + "advanced": 22, + "elite": 29 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 12, + "beginner": 15, + "intermediate": 19, + "advanced": 25, + "elite": 35 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 13, + "beginner": 17, + "intermediate": 21, + "advanced": 28, + "elite": 37 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 14, + "beginner": 19, + "intermediate": 23, + "advanced": 30, + "elite": 40 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 15, + "beginner": 21, + "intermediate": 24, + "advanced": 33, + "elite": 44 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 16, + "beginner": 23, + "intermediate": 26, + "advanced": 35, + "elite": 45 + }, + { + "age": 65, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 18, + "beginner": 25, + "intermediate": 29, + "advanced": 38, + "elite": 49 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 9, + "beginner": 11, + "intermediate": 14, + "advanced": 18, + "elite": 25 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 10, + "beginner": 13, + "intermediate": 16, + "advanced": 21, + "elite": 29 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 11, + "beginner": 15, + "intermediate": 18, + "advanced": 23, + "elite": 32 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 12, + "beginner": 16, + "intermediate": 19, + "advanced": 25, + "elite": 34 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 13, + "beginner": 18, + "intermediate": 21, + "advanced": 28, + "elite": 37 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 14, + "beginner": 19, + "intermediate": 22, + "advanced": 29, + "elite": 38 + }, + { + "age": 75, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 16, + "beginner": 21, + "intermediate": 24, + "advanced": 33, + "elite": 41 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 57, + "physicallyActive": 6, + "beginner": 8, + "intermediate": 10, + "advanced": 13, + "elite": 17 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 68, + "physicallyActive": 7, + "beginner": 9, + "intermediate": 11, + "advanced": 15, + "elite": 20 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 79, + "physicallyActive": 8, + "beginner": 10, + "intermediate": 12, + "advanced": 16, + "elite": 22 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 91, + "physicallyActive": 8, + "beginner": 11, + "intermediate": 13, + "advanced": 17, + "elite": 23 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 102, + "physicallyActive": 9, + "beginner": 12, + "intermediate": 14, + "advanced": 19, + "elite": 26 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 113, + "physicallyActive": 9, + "beginner": 13, + "intermediate": 15, + "advanced": 20, + "elite": 26 + }, + { + "age": 85, + "activityType": "Strict Press", + "gender": "female", + "bodyWeight": 136, + "physicallyActive": 11, + "beginner": 15, + "intermediate": 17, + "advanced": 22, + "elite": 29 + }, + { + "age": 10, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 676000, + "beginner": 560000, + "intermediate": 475000, + "advanced": 414000, + "elite": 369000 + }, + { + "age": 15, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 585000, + "beginner": 485000, + "intermediate": 411000, + "advanced": 358000, + "elite": 319000 + }, + { + "age": 20, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 565000, + "beginner": 468000, + "intermediate": 398000, + "advanced": 346000, + "elite": 308000 + }, + { + "age": 25, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 565000, + "beginner": 468000, + "intermediate": 398000, + "advanced": 346000, + "elite": 308000 + }, + { + "age": 30, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 566000, + "beginner": 469000, + "intermediate": 398000, + "advanced": 346000, + "elite": 309000 + }, + { + "age": 35, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 575000, + "beginner": 476000, + "intermediate": 404000, + "advanced": 352000, + "elite": 314000 + }, + { + "age": 40, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 595000, + "beginner": 493000, + "intermediate": 418000, + "advanced": 364000, + "elite": 325000 + }, + { + "age": 45, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 617000, + "beginner": 511000, + "intermediate": 434000, + "advanced": 378000, + "elite": 337000 + }, + { + "age": 50, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 642000, + "beginner": 531000, + "intermediate": 451000, + "advanced": 393000, + "elite": 350000 + }, + { + "age": 55, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 668000, + "beginner": 553000, + "intermediate": 469000, + "advanced": 409000, + "elite": 364000 + }, + { + "age": 60, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 696000, + "beginner": 577000, + "intermediate": 489000, + "advanced": 426000, + "elite": 380000 + }, + { + "age": 65, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 727000, + "beginner": 602000, + "intermediate": 511000, + "advanced": 445000, + "elite": 397000 + }, + { + "age": 70, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 763000, + "beginner": 632000, + "intermediate": 537000, + "advanced": 467000, + "elite": 417000 + }, + { + "age": 75, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 820000, + "beginner": 680000, + "intermediate": 577000, + "advanced": 502000, + "elite": 448000 + }, + { + "age": 80, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 908000, + "beginner": 752000, + "intermediate": 638000, + "advanced": 556000, + "elite": 495000 + }, + { + "age": 85, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 1045000, + "beginner": 866000, + "intermediate": 735000, + "advanced": 640000, + "elite": 570000 + }, + { + "age": 90, + "activityType": "Run", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 1273000, + "beginner": 1055000, + "intermediate": 895000, + "advanced": 779000, + "elite": 695000 + }, + { + "age": 10, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 749000, + "beginner": 632000, + "intermediate": 543000, + "advanced": 477000, + "elite": 428000 + }, + { + "age": 15, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 672000, + "beginner": 567000, + "intermediate": 488000, + "advanced": 428000, + "elite": 384000 + }, + { + "age": 20, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 640000, + "beginner": 540000, + "intermediate": 464000, + "advanced": 408000, + "elite": 366000 + }, + { + "age": 25, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 640000, + "beginner": 540000, + "intermediate": 464000, + "advanced": 408000, + "elite": 366000 + }, + { + "age": 30, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 640000, + "beginner": 540000, + "intermediate": 464000, + "advanced": 408000, + "elite": 366000 + }, + { + "age": 35, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 644000, + "beginner": 544000, + "intermediate": 467000, + "advanced": 410000, + "elite": 368000 + }, + { + "age": 40, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 658000, + "beginner": 555000, + "intermediate": 477000, + "advanced": 419000, + "elite": 376000 + }, + { + "age": 45, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 681000, + "beginner": 575000, + "intermediate": 494000, + "advanced": 434000, + "elite": 389000 + }, + { + "age": 50, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 716000, + "beginner": 604000, + "intermediate": 520000, + "advanced": 456000, + "elite": 409000 + }, + { + "age": 55, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 757000, + "beginner": 639000, + "intermediate": 550000, + "advanced": 482000, + "elite": 433000 + }, + { + "age": 60, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 804000, + "beginner": 678000, + "intermediate": 583000, + "advanced": 512000, + "elite": 459000 + }, + { + "age": 65, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 856000, + "beginner": 722000, + "intermediate": 621000, + "advanced": 545000, + "elite": 489000 + }, + { + "age": 70, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 915000, + "beginner": 772000, + "intermediate": 664000, + "advanced": 583000, + "elite": 523000 + }, + { + "age": 75, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 983000, + "beginner": 830000, + "intermediate": 713000, + "advanced": 626000, + "elite": 562000 + }, + { + "age": 80, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 1065000, + "beginner": 898000, + "intermediate": 772000, + "advanced": 678000, + "elite": 608000 + }, + { + "age": 85, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 1199000, + "beginner": 1012000, + "intermediate": 870000, + "advanced": 763000, + "elite": 685000 + }, + { + "age": 90, + "activityType": "Run", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 1445000, + "beginner": 1219000, + "intermediate": 1048000, + "advanced": 920000, + "elite": 825000 + }, + { + "age": 18, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 14000, + "beginner": 13000, + "intermediate": 12000, + "advanced": 11300, + "elite": 10800 + }, + { + "age": 40, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 14500, + "beginner": 13500, + "intermediate": 12400, + "advanced": 11700, + "elite": 11200 + }, + { + "age": 45, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 15700, + "beginner": 14500, + "intermediate": 13400, + "advanced": 12600, + "elite": 12100 + }, + { + "age": 50, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 15900, + "beginner": 14800, + "intermediate": 13600, + "advanced": 12800, + "elite": 12300 + }, + { + "age": 55, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 16500, + "beginner": 15300, + "intermediate": 14200, + "advanced": 13300, + "elite": 12700 + }, + { + "age": 60, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 17100, + "beginner": 15900, + "intermediate": 14700, + "advanced": 13800, + "elite": 13200 + }, + { + "age": 65, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 18000, + "beginner": 16700, + "intermediate": 15400, + "advanced": 14500, + "elite": 13900 + }, + { + "age": 70, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 18400, + "beginner": 17100, + "intermediate": 15800, + "advanced": 14900, + "elite": 14200 + }, + { + "age": 75, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 19400, + "beginner": 18000, + "intermediate": 16600, + "advanced": 15600, + "elite": 14900 + }, + { + "age": 80, + "activityType": "Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 20800, + "beginner": 19300, + "intermediate": 17800, + "advanced": 16800, + "elite": 16100 + }, + { + "age": 18, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 15400, + "beginner": 14300, + "intermediate": 13300, + "advanced": 12500, + "elite": 11900 + }, + { + "age": 40, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 16100, + "beginner": 14900, + "intermediate": 13900, + "advanced": 13100, + "elite": 12400 + }, + { + "age": 45, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 16500, + "beginner": 15300, + "intermediate": 14200, + "advanced": 13400, + "elite": 12700 + }, + { + "age": 50, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 16900, + "beginner": 15700, + "intermediate": 14600, + "advanced": 13700, + "elite": 13100 + }, + { + "age": 55, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 17600, + "beginner": 16400, + "intermediate": 15200, + "advanced": 14300, + "elite": 13600 + }, + { + "age": 60, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 19200, + "beginner": 17800, + "intermediate": 16500, + "advanced": 15600, + "elite": 14800 + }, + { + "age": 65, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 20200, + "beginner": 18700, + "intermediate": 17400, + "advanced": 16400, + "elite": 15600 + }, + { + "age": 70, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 21400, + "beginner": 19900, + "intermediate": 18500, + "advanced": 17400, + "elite": 16500 + }, + { + "age": 75, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 21800, + "beginner": 20300, + "intermediate": 18800, + "advanced": 17700, + "elite": 16900 + }, + { + "age": 80, + "activityType": "Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 23600, + "beginner": 21900, + "intermediate": 20300, + "advanced": 19100, + "elite": 18200 + }, + { + "age": 18, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.007142857142857143, + "beginner": 0.007692307692307693, + "intermediate": 0.008333333333333333, + "advanced": 0.008849557522123894, + "elite": 0.009259259259259259 + }, + { + "age": 40, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.006896551724137931, + "beginner": 0.007407407407407408, + "intermediate": 0.008064516129032258, + "advanced": 0.008547008547008548, + "elite": 0.008928571428571428 + }, + { + "age": 45, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.006369426751592357, + "beginner": 0.006896551724137931, + "intermediate": 0.007462686567164179, + "advanced": 0.007936507936507936, + "elite": 0.008264462809917356 + }, + { + "age": 50, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.006289308176100629, + "beginner": 0.006756756756756757, + "intermediate": 0.007352941176470588, + "advanced": 0.0078125, + "elite": 0.008130081300813009 + }, + { + "age": 55, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.006060606060606061, + "beginner": 0.006535947712418301, + "intermediate": 0.007042253521126761, + "advanced": 0.007518796992481203, + "elite": 0.007874015748031496 + }, + { + "age": 60, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.005847953216374269, + "beginner": 0.006289308176100629, + "intermediate": 0.006802721088435374, + "advanced": 0.007246376811594203, + "elite": 0.007575757575757576 + }, + { + "age": 65, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.005555555555555556, + "beginner": 0.005988023952095809, + "intermediate": 0.006493506493506494, + "advanced": 0.006896551724137931, + "elite": 0.007194244604316547 + }, + { + "age": 70, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.005434782608695652, + "beginner": 0.005847953216374269, + "intermediate": 0.006329113924050633, + "advanced": 0.006711409395973154, + "elite": 0.007042253521126761 + }, + { + "age": 75, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.005154639175257732, + "beginner": 0.005555555555555556, + "intermediate": 0.006024096385542169, + "advanced": 0.00641025641025641, + "elite": 0.006711409395973154 + }, + { + "age": 80, + "activityType": "Treadmill Dash", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 0.004807692307692308, + "beginner": 0.0051813471502590676, + "intermediate": 0.0056179775280898875, + "advanced": 0.005952380952380952, + "elite": 0.006211180124223602 + }, + { + "age": 18, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.006493506493506494, + "beginner": 0.006993006993006993, + "intermediate": 0.007518796992481203, + "advanced": 0.008, + "elite": 0.008403361344537815 + }, + { + "age": 40, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.006211180124223602, + "beginner": 0.006711409395973154, + "intermediate": 0.007194244604316547, + "advanced": 0.007633587786259542, + "elite": 0.008064516129032258 + }, + { + "age": 45, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.006060606060606061, + "beginner": 0.006535947712418301, + "intermediate": 0.007042253521126761, + "advanced": 0.007462686567164179, + "elite": 0.007874015748031496 + }, + { + "age": 50, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.005917159763313609, + "beginner": 0.006369426751592357, + "intermediate": 0.00684931506849315, + "advanced": 0.0072992700729927005, + "elite": 0.007633587786259542 + }, + { + "age": 55, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.005681818181818182, + "beginner": 0.006097560975609756, + "intermediate": 0.006578947368421052, + "advanced": 0.006993006993006993, + "elite": 0.007352941176470588 + }, + { + "age": 60, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.005208333333333333, + "beginner": 0.0056179775280898875, + "intermediate": 0.006060606060606061, + "advanced": 0.00641025641025641, + "elite": 0.006756756756756757 + }, + { + "age": 65, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.0049504950495049506, + "beginner": 0.0053475935828877, + "intermediate": 0.005747126436781609, + "advanced": 0.006097560975609756, + "elite": 0.00641025641025641 + }, + { + "age": 70, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.004672897196261682, + "beginner": 0.005025125628140704, + "intermediate": 0.005405405405405406, + "advanced": 0.005747126436781609, + "elite": 0.006060606060606061 + }, + { + "age": 75, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.0045871559633027525, + "beginner": 0.0049261083743842365, + "intermediate": 0.005319148936170213, + "advanced": 0.005649717514124294, + "elite": 0.005917159763313609 + }, + { + "age": 80, + "activityType": "Treadmill Dash", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 0.00423728813559322, + "beginner": 0.0045662100456621, + "intermediate": 0.0049261083743842365, + "advanced": 0.005235602094240838, + "elite": 0.005494505494505495 + }, + { + "age": 18, + "activityType": "Broad Jump", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 200, + "beginner": 214, + "intermediate": 224, + "advanced": 234, + "elite": 245 + }, + { + "age": 18, + "activityType": "Broad Jump", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 150, + "beginner": 164, + "intermediate": 174, + "advanced": 184, + "elite": 194 + }, + { + "age": 18, + "activityType": "Cone Drill", + "gender": "male", + "bodyWeight": -1, + "physicallyActive": 9500, + "beginner": 8700, + "intermediate": 7800, + "advanced": 7000, + "elite": 6500 + }, + { + "age": 18, + "activityType": "Cone Drill", + "gender": "female", + "bodyWeight": -1, + "physicallyActive": 10500, + "beginner": 9600, + "intermediate": 8700, + "advanced": 7800, + "elite": 7200 + } +] diff --git a/api/calculator/util.ts b/api/calculator/util.ts new file mode 100644 index 0000000..fdbb598 --- /dev/null +++ b/api/calculator/util.ts @@ -0,0 +1,139 @@ +// ------------------------------------------------------------------------------------------------- +// Enumerations & basic value objects +// ------------------------------------------------------------------------------------------------- +export const activities = Object.freeze({ + BACK_SQUAT: "Back Squat", + DEADLIFT: "Deadlift", + BENCH_PRESS: "Bench Press", + RUN: "Run", + DASH: "Dash", + TREADMILL_DASH: "Treadmill Dash", + BROAD_JUMP: "Broad Jump", + CONE_DRILL: "Cone Drill", +} as const); + +export type Activity = typeof activities[keyof typeof activities]; + +export const genders = Object.freeze({ + MALE: "male", + FEMALE: "female", +} as const); +export type Gender = typeof genders[keyof typeof genders]; + +// ------------------------------------------------------------------------------------------------- +// Attributes +// ------------------------------------------------------------------------------------------------- + +export const attributes = Object.freeze({ + STRENGTH: "Strength", + POWER: "Power", + ENDURANCE: "Endurance", + SPEED: "Speed", + AGILITY: "Agility", +} as const); +export type Attribute = typeof attributes[keyof typeof attributes]; + +export const getActivityAttribute = (activity: Activity): Attribute => { + const activityAttrMap: Record = { + [activities.RUN]: attributes.ENDURANCE, + [activities.TREADMILL_DASH]: attributes.SPEED, + [activities.DASH]: attributes.SPEED, + [activities.DEADLIFT]: attributes.STRENGTH, + [activities.BACK_SQUAT]: attributes.STRENGTH, + [activities.BENCH_PRESS]: attributes.STRENGTH, + [activities.BROAD_JUMP]: attributes.POWER, + [activities.CONE_DRILL]: attributes.AGILITY, + } as const; + + const attribute = activityAttrMap[activity]; + if (!attribute) throw new Error(`${activity} does not have an associated attribute`); + return attribute; +}; + +// ------------------------------------------------------------------------------------------------- +// Data model interfaces +// ------------------------------------------------------------------------------------------------- +export interface BenchmarkPerformance { + activity: Activity; + performance: number; + /** + * Key: level number, Value: performance value (kg, ms, m/s, etc.) + */ + levels: Record; +} + +export interface Levels { + /** KG or -1 for body‑weight‑agnostic entries */ + physicallyActive: number; + beginner: number; + intermediate: number; + advanced: number; + elite: number; +} + +export interface StandardsItem extends Levels { + bodyWeight: number; + gender: Gender; + activityType: Activity; + age: number; +} + +// ------------------------------------------------------------------------------------------------- +// Conversion utilities +// ------------------------------------------------------------------------------------------------- +export const lbToKg = (lb: number | string): number => +lb * 0.453592; +export const kgToLb = (kg: number | string): number => +kg * 2.20462; + +export const feetToCm = (feet: number): number => feet * 30.48; + +export const mphToMtrsPerMs = (mph: number): number => (mph * 0.44704) / 1000; + +export const timeToMs = (time: string): number => { + const [main, decimal = "0"] = time.split("."); + const milliseconds = Number(decimal.padEnd(3, "0").slice(0, 3)); + + const parts = main.split(":").map(Number); + let minutes = 0, + seconds = 0; + + if (parts.length === 1) { + seconds = parts[0]; + } else if (parts.length === 2) { + [minutes, seconds] = parts as [number, number]; + } else { + throw new Error("Invalid time format"); + } + + return (minutes * 60 + seconds) * 1000 + milliseconds; +}; + +export const msToTime = (ms: number, includeMs = false): string => { + const minutes = Math.floor(ms / 60000); + const seconds = Math.floor((ms % 60000) / 1000); + const milliseconds = Math.floor(ms % 1000); + + let formattedTime = `${minutes}:${seconds.toString().padStart(2, "0")}`; + if (includeMs) { + formattedTime += `.${milliseconds.toString().padStart(3, "0")}`; + } + return formattedTime; +}; + +// ------------------------------------------------------------------------------------------------- +// Misc. utilities +// ------------------------------------------------------------------------------------------------- + +export const findNearestPoints = (value: number, arr: number[]): { lower: number; upper: number } => { + if (arr.length === 1) return { lower: arr[0], upper: arr[0] }; + + if (value <= arr[0]) return { lower: arr[0], upper: arr[1] }; + if (value > arr[arr.length - 1]) + return { lower: arr[arr.length - 2], upper: arr[arr.length - 1] }; + + for (let i = 1; i < arr.length; i++) { + if (arr[i] >= value) return { lower: arr[i - 1], upper: arr[i] }; + } + // Fallback, though logic should always return above + return { lower: arr[0], upper: arr[0] }; +}; + diff --git a/api/commerce/data/data.db b/api/commerce/data/data.db new file mode 100644 index 0000000..9073ddb Binary files /dev/null and b/api/commerce/data/data.db differ diff --git a/api/commerce/data/product-records.ts b/api/commerce/data/product-records.ts new file mode 100644 index 0000000..46d826b --- /dev/null +++ b/api/commerce/data/product-records.ts @@ -0,0 +1,59 @@ +import { Database } from "bun:sqlite"; + +interface ProductRecord { + webflowProductId: number; + printfulProductId: number; +} + +class ProductRecords { + private db: Database; + + constructor() { + const dbPath = Bun.env.NODE_ENV === "production" ? + "/data/data.db" : + "./data/data.db"; + + this.db = new Database(dbPath); + } + + findFromWebflow(webflowProductId: number): ProductRecord | undefined { + const row = this.db.query(` + SELECT * FROM product_records WHERE webflowProductId = ? + `).get(webflowProductId); + + return row as ProductRecord | undefined; + } + + findFromPrintful(printfulProductId: number): ProductRecord | undefined { + const row = this.db.query(` + SELECT * FROM product_records WHERE printfulProductId = ? + `).get(printfulProductId); + + return row as ProductRecord | undefined; + } + + deleteFromWebflow(webflowProductId: number) { + this.db.run(` + DELETE FROM product_records WHERE webflowProductId = ? + `, [webflowProductId]); + } + + deleteFromPrintful(printfulProductId: number) { + this.db.run(` + DELETE FROM product_records WHERE printfulProductId = ? + `, [printfulProductId]); + } + + add(record: ProductRecord): void { + this.db.run(` + INSERT OR IGNORE INTO product_records (webflowProductId, printfulProductId) + VALUES (?, ?) + `, [record.webflowProductId, record.printfulProductId]); + } + + all(): ProductRecord[] { + return this.db.query(`SELECT * FROM product_records`).all() as ProductRecord[]; + } +} + +export const productRecords = new ProductRecords(); diff --git a/api/commerce/data/seed.sql b/api/commerce/data/seed.sql new file mode 100644 index 0000000..f01665a --- /dev/null +++ b/api/commerce/data/seed.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS product_records ( + webflowProductId INTEGER NOT NULL, + printfulProductId INTEGER NOT NULL, + UNIQUE(webflowProductId, printfulProductId) +) diff --git a/api/commerce/printful.ts b/api/commerce/printful.ts new file mode 100644 index 0000000..9744046 --- /dev/null +++ b/api/commerce/printful.ts @@ -0,0 +1,134 @@ +export namespace Printful { + export const API_URL = "https://api.printful.com"; + + export namespace Webhook { + // meta + interface MetaData { + created: number; + retries: number; + store: number; + } + + export enum Event { + ProductUpdated = "product_updated", + ProductDeleted = "product_deleted" + } + + // product updated + export interface ProductUpdated extends MetaData { + type: Event.ProductUpdated, + data: { + sync_product: { + id: number; + external_id: string; + name: string; + variants: number; + synced: number; + thumbnail_url: string; + is_ignored: boolean; + }; + } + } + + // product deleted + export interface ProductDeleted extends MetaData { + type: Event.ProductDeleted, + data: { + sync_product: { + id: number; + external_id: string; + name: string; + }; + } + } + + export type EventPayload = ProductUpdated | ProductDeleted + } + + export namespace Products { + interface MetaData { + code: number; + result: T; + } + + interface Option { + id: string; + value: string; + } + + interface File { + type: string; + id: number; + url: string; + options: Option[]; + hash: string; + filename: string; + mime_type: string; + size: number; + width: number; + height: number; + dpi: number; + status: string; + created: number; + thumbnail_url: string; + preview_url: string; + visible: boolean; + is_temporary: boolean; + stitch_count_tier: string; + } + + interface SyncProductData { + sync_product: { + id: number; + external_id: string; + name: string; + variants: number; + synced: number; + thumbnail_url: string; + is_ignored: boolean; + }, + sync_variants: { + id: number; + external_id: string; + sync_product_id: number; + name: string; + synced: boolean; + variant_id: number; + retail_price: string; + currency: string; + is_ignored: boolean; + sku: string; + product: { + variant_id: number; + product_id: number; + image: string; + name: string; + }; + files: File[]; + options: Option[]; + main_category_id: number; + warehouse_product_id: number; + warehouse_product_variant_id: number; + size: string; + color: string; + availability_status: string; + + }[] + } + export type SyncProduct = MetaData; + } + + export async function getSyncProduct(syncProductId: number): Promise { + const payload: Products.SyncProduct = await ( + await fetch(`${Printful.API_URL}/store/products/${syncProductId}`, { + method: "GET", + headers: { + "Authorization": `Bearer ${Bun.env.PRINTFUL_AUTH}`, + "X-PF-Store-Id": `${Bun.env.PRINTFUL_STORE_ID}` + } + }) + ).json(); + + return payload; + } +} diff --git a/api/commerce/webflow.ts b/api/commerce/webflow.ts new file mode 100644 index 0000000..e3f0dbd --- /dev/null +++ b/api/commerce/webflow.ts @@ -0,0 +1,276 @@ +import { productRecords } from "./data/product-records"; +import { Printful } from "./printful" + +export namespace Webflow { + export const API_SITES_URL = `https://api.webflow.com/v2/sites/${Bun.env.WEBFLOW_SITE_ID}`; + export const API_COLLECTIONS_URL = `https://api.webflow.com/v2/collections/${Bun.env.WEBFLOW_COLLECTION_ID}`; + + const formatSlug = (name: string): string => { + return name + .toLowerCase() + .replace(/[^a-z0-9-_]/g, '-') // replace illegal chars with dashes + .replace(/^-+/, '') // remove leading dashes + .replace(/-+$/, '') // remove trailing dashes + .replace(/--+/g, '-') // collapse multiple dashes + .replace(/^([^a-z0-9_])/, '_$1'); // if it starts with an invalid char, prefix underscore + }; + + namespace Products { + export interface Sku { + fieldData: { + name: string; + slug: string; + "sku-values"?: Record, + price: { + value: number; + unit: string; + currency: string; + }; + "main-image": string; + } + } + + export interface CreateProduct { + product: { + fieldData: { + name: string; + slug: string; + description: string; + "sku-properties": { + id: string; + name: string; + enum: { + id: string; + name: string; + slug: string; + }[]; + }[]; + } + }; + sku: Sku; + publishStatus: string; + } + } + + export async function deleteProductFromPrintful(printfulProductId: number) { + const webflowProductId = productRecords.findFromPrintful(printfulProductId)?.webflowProductId; + if (webflowProductId) { + const res = await fetch(`${Webflow.API_COLLECTIONS_URL}/items/${webflowProductId}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + "Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}` + }, + body: JSON.stringify({}) + }); + productRecords.deleteFromWebflow(webflowProductId); + } + } + + export async function updateProductFromPrintful(printfulProduct: Printful.Products.SyncProduct) { + const webflowProductId = productRecords.findFromPrintful(printfulProduct.result.sync_product.id)?.webflowProductId; + if (!webflowProductId) { + throw new Error("Product is not recognized"); + } + + const printfulVariants = printfulProduct.result.sync_variants; + const webflowVariants: Products.Sku[] = []; + for (const printfulVariant of printfulVariants) { + webflowVariants.push({ + "fieldData": { + "name": printfulVariant.name, + "slug": formatSlug(printfulVariant.name), + "sku-values": { + "color": printfulVariant.color, + "size": printfulVariant.size, + }, + "price": { + "value": +printfulVariant.retail_price * 100, + "unit": printfulVariant.currency, + "currency": printfulVariant.currency + }, + // TODO: sync image + "main-image": "https://www.example.com/image.jpg" + } + }); + } + + const foundColors = Array.from(new Set(printfulVariants.map(v => v.color))); + const foundSizes = Array.from(new Set(printfulVariants.map(v => v.size))); + + let updateProductResponse = await fetch(`${Webflow.API_SITES_URL}/products/${webflowProductId}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + "Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}`, + }, + body: JSON.stringify({ + "product": { + "fieldData": { + "name": printfulProduct.result.sync_product.name, + "slug": formatSlug(printfulProduct.result.sync_product.name), + "sku-properties": [ + { + "id": "color", + "name": "Color", + "enum": foundColors.map(color => ({ + "id": color, + "slug": formatSlug(color), + "name": color + })) + }, + { + "id": "size", + "name": "Size", + "enum": foundSizes.map(size => ({ + "id": size, + "slug": formatSlug(size), + "name": size + })) + }, + ] + } + }, + "sku": webflowVariants[0] + }) + }); + updateProductResponse = await updateProductResponse.json(); + + const getProductResponse = await fetch(`${Webflow.API_SITES_URL}/products/${webflowProductId}`, { + method: "GET", + headers: { + "Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}` + } + }); + const webflowProduct = await getProductResponse.json(); + + for (let i = 0; i < webflowProduct["skus"].length; ++i) { + const webflowSkuId = printfulVariants[i].external_id; + + const res = await fetch(`${Webflow.API_SITES_URL}/products/${webflowProductId}/skus/${webflowSkuId}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + "Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}` + }, + body: JSON.stringify({ + "sku": webflowVariants[i] + }) + }); + console.log(JSON.stringify((await res.json()))); + } + } + + export async function createProductFromPrintful(printfulProduct: Printful.Products.SyncProduct) { + const printfulVariants = printfulProduct.result.sync_variants; + + const webflowVariants: Products.Sku[] = []; + for (const printfulVariant of printfulVariants) { + webflowVariants.push({ + "fieldData": { + "name": printfulVariant.name, + "slug": formatSlug(printfulVariant.name), + "sku-values": { + "color": printfulVariant.color, + "size": printfulVariant.size, + }, + "price": { + "value": +printfulVariant.retail_price * 100, + "unit": printfulVariant.currency, + "currency": printfulVariant.currency + }, + // TODO: sync image + "main-image": "https://www.example.com/image.jpg" + } + }); + } + + const foundColors = Array.from(new Set(printfulVariants.map(v => v.color))); + const foundSizes = Array.from(new Set(printfulVariants.map(v => v.size))); + + // CREATE WEBFLOW PRODUCT + let addProductResponse = await (await fetch(`${Webflow.API_SITES_URL}/products`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}`, + }, + body: JSON.stringify({ + "product": { + "fieldData": { + "name": printfulProduct.result.sync_product.name, + "slug": formatSlug(printfulProduct.result.sync_product.name), + "sku-properties": [ + { + "id": "color", + "name": "Color", + "enum": foundColors.map(color => ({ + "id": color, + "slug": formatSlug(color), + "name": color + })) + }, + { + "id": "size", + "name": "Size", + "enum": foundSizes.map(size => ({ + "id": size, + "slug": formatSlug(size), + "name": size + })) + }, + ] + } + }, + "sku": webflowVariants[0], + }) + }))?.json(); + + if (!addProductResponse?.product?.id) { + console.error("Webflow product creation failed:", addProductResponse); + throw new Error("Failed to create Webflow product"); + } + + const webflowProductId = addProductResponse["product"]["id"]; + const printfulProductId = printfulProduct.result.sync_product.id; + + // CREATE WEBFLOW PRODUCT SKUs + let createSkuResponse = await fetch(`${Webflow.API_SITES_URL}/products/${webflowProductId}/skus`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}` + }, + body: JSON.stringify({ + "skus": webflowVariants.slice(1) + }) + }); + createSkuResponse = await createSkuResponse.json(); + + const responseSkus = [addProductResponse["sku"], ...createSkuResponse["skus"]]; + + // SYNC WEBFLOW/PRINTFUL PRODUCT AND VARIANT IDs + let modifyPrintfulProductResponse = await fetch(`${Printful.API_URL}/store/products/${printfulProductId}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${Bun.env.PRINTFUL_AUTH}`, + "X-PF-Store-Id": Bun.env.PRINTFUL_STORE_ID ?? "" + }, + body: JSON.stringify({ + "sync_product": { + "external_id": String(webflowProductId) + }, + "sync_variants": responseSkus.map((sku, i) => ({ + "id": Number(printfulVariants[i].id), // printful variant id + "external_id": String(sku.id), // webflow variant id + })) + }) + }); + modifyPrintfulProductResponse = await modifyPrintfulProductResponse.json(); + + // CACHE WEBFLOW/PRINTFUL PRODUCT ASSOCIATION + productRecords.add({ printfulProductId, webflowProductId }); + } +} + diff --git a/api/fly.toml b/api/fly.toml new file mode 100644 index 0000000..695367f --- /dev/null +++ b/api/fly.toml @@ -0,0 +1,29 @@ +# fly.toml app configuration file generated for blade-and-brawn on 2025-05-04T14:56:24-04:00 +# +# See https://fly.io/docs/reference/configuration/ for information about how to use this file. +# + +app = 'blade-and-brawn' +primary_region = 'ord' + +[build] + +[env] + PORT = '8080' + +[http_service] + internal_port = 8080 + force_https = true + auto_stop_machines = 'stop' + auto_start_machines = true + min_machines_running = 0 + processes = ['app'] + +[[vm]] + memory = '1gb' + cpu_kind = 'shared' + cpus = 1 + +[[mounts]] + source = "data" + destination = "/data" \ No newline at end of file diff --git a/api/main.ts b/api/main.ts new file mode 100644 index 0000000..872d378 --- /dev/null +++ b/api/main.ts @@ -0,0 +1,110 @@ +import { calcAttributeLevels, calcPlayerLevel, computeLevels } from "./calculator/calc.ts"; +import { Activity, BenchmarkPerformance, Gender } from "./calculator/util.ts"; +import { productRecords } from "./commerce/data/product-records.ts"; +import { Printful } from "./commerce/printful.ts" +import { Webflow } from "./commerce/webflow.ts"; + +interface CalcRequest { + player: { + age: number, + weightKG: number, + gender: Gender + } + performances: { + activity: Activity, + performance: number, + }[] +} + +export class ClientResponse extends Response { + constructor(body?: BodyInit | null, init: ResponseInit = {}) { + const headers = new Headers(init.headers); + headers.set("Access-Control-Allow-Origin", "*"); + headers.set("Access-Control-Allow-Methods", "POST, OPTIONS"); + headers.set("Access-Control-Allow-Headers", "Content-Type"); + super(body, { ...init, headers }); + } + + static json(data: unknown, init: ResponseInit = {}) { + const body = JSON.stringify(data); + const headers = new Headers(init.headers); + headers.set("Content-Type", "application/json"); + return new ClientResponse(body, { ...init, headers }); + } +} + +const server = Bun.serve({ + routes: { + "/calc": { + OPTIONS() { + return new ClientResponse(undefined, { status: 204 }); + }, + async POST(req) { + const calcReq: CalcRequest = await req.json(); + const { player, performances } = calcReq; + + const computedPerformances: BenchmarkPerformance[] = []; + for (const p of performances) { + computedPerformances.push({ + activity: p.activity, + performance: p.performance, + levels: computeLevels( + player.age, + player.weightKG, + player.gender, + p.activity + ) + }) + } + + return ClientResponse.json({ + levels: { + attributes: calcAttributeLevels(computedPerformances), + player: calcPlayerLevel(computedPerformances) + } + }) + } + }, + "/webhook/printful": { + OPTIONS() { + return new ClientResponse(undefined, { status: 204 }); + }, + async POST(req) { + const payload: Printful.Webhook.EventPayload = await req.json() + console.log(JSON.stringify(payload)); + console.log("PRINTFUL WEBHOOK: " + payload.type); + try { + switch (payload.type) { + // ADD/UPDATE + case Printful.Webhook.Event.ProductUpdated: { + const printfulProduct = await Printful.getSyncProduct(payload.data.sync_product.id); + const productRecord = productRecords.findFromPrintful(payload.data.sync_product.id); + + if (productRecord) { + await Webflow.updateProductFromPrintful(printfulProduct); + } + else { + await Webflow.createProductFromPrintful(printfulProduct); + } + break; + } + // DELETE + case Printful.Webhook.Event.ProductDeleted: { + await Webflow.deleteProductFromPrintful(payload.data.sync_product.id); + break; + } + } + } + catch (error) { + console.error(error); + ClientResponse.error(); + } + + return ClientResponse.json(""); + } + } + }, + development: true +}) + +console.log(`Listening on ${server.url}`); diff --git a/api/package.json b/api/package.json new file mode 100644 index 0000000..4ed378a --- /dev/null +++ b/api/package.json @@ -0,0 +1,11 @@ +{ + "dependencies": {}, + "devDependencies": { + "@types/bun": "^1.2.11" + }, + "scripts": { + "db:seed:dev": "sqlite3 ./data/data.db < ./data/seed.sql", + "db:seed:prod": "sqlite3 /data/data.db < ./data/seed.sql", + "start": "bun run main.ts" + } +} diff --git a/main.ts b/main.ts index eb95529..dca7630 100644 --- a/main.ts +++ b/main.ts @@ -73,8 +73,6 @@ const server = Bun.serve({ }, async POST(req) { const payload: Printful.Webhook.EventPayload = await req.json() - console.log(JSON.stringify(payload)); - console.log("PRINTFUL WEBHOOK: " + payload.type); try { switch (payload.type) { // ADD/UPDATE diff --git a/website/audio/knight.ogg b/website/audio/knight.ogg new file mode 100644 index 0000000..9f72882 Binary files /dev/null and b/website/audio/knight.ogg differ diff --git a/website/audio/rogue.ogg b/website/audio/rogue.ogg new file mode 100644 index 0000000..f37b663 Binary files /dev/null and b/website/audio/rogue.ogg differ diff --git a/website/audio/warrior.ogg b/website/audio/warrior.ogg new file mode 100644 index 0000000..602afd7 Binary files /dev/null and b/website/audio/warrior.ogg differ diff --git a/website/index.html b/website/index.html new file mode 100644 index 0000000..a3933e8 --- /dev/null +++ b/website/index.html @@ -0,0 +1,22 @@ + + + + + + + + + + + +

None

+
+ + + +
+ +
+ + + diff --git a/website/main.js b/website/main.js new file mode 100644 index 0000000..7971312 --- /dev/null +++ b/website/main.js @@ -0,0 +1,96 @@ +const $ = (id) => document.getElementById(id); + +let currentAudio = null; +function playAudio(newAudio) { + // -------------- + // HELPERS + // -------------- + const TIME_STEP = 500; + const VOL_STEP = .05; + + function fadeOut(audio) { + const intervalId = setInterval(() => { + audio.volume = Math.max(0, audio.volume - VOL_STEP); + if (audio.volume <= 0) { + clearInterval(intervalId); + } + }, TIME_STEP) + } + + function fadeIn(audio) { + audio.volume = 0; + audio.play(); + const intervalId = setInterval(() => { + audio.volume = Math.min(1, audio.volume + VOL_STEP); + if (audio.volume >= 1) { + clearInterval(intervalId); + } + }, TIME_STEP) + } + // -------------- + + // -------------- + // MAIN LOGIC + // -------------- + + const prevAudio = currentAudio; + + if (prevAudio === newAudio) + return; + + if (prevAudio) { + fadeOut(prevAudio); + } + + fadeIn(newAudio); + + currentAudio = newAudio; + // -------------- +} + +document.addEventListener("DOMContentLoaded", async function() { + const $ = (id) => document.getElementById(id); + + const classNames = ["rogue", "knight", "warrior"]; + const audios = {}; + + for (const className of classNames) { + const audio = document.createElement("audio"); + audio.src = `https://bladeandbrawn.com/${className}.ogg`; + audio.loop = true; + audio.volume = 0; + audio.id = `audio-${className}`; + $("audioContainer").appendChild(audio); + audios[className] = audio; + } + + await Promise.all(classNames.map(async (className) => { + const audio = audios[className]; + try { + await audio.play(); + audio.pause(); + audio.currentTime = 0; + } catch (e) { + console.warn(`Autoplay failed for ${className}:`, e); + } + })); + + // Start all in perfect sync + classNames.forEach(className => { + const audio = audios[className]; + audio.currentTime = 0; + audio.play(); + }); + + // Hook up buttons + classNames.forEach(className => { + $(`btn-${className}`).onclick = () => { + $("currentClass").textContent = className; + playAudio(audios[className]); + }; + }); + + // Set initial state + $("currentClass").textContent = "rogue"; + playAudio(audios["rogue"]); +});