diff --git a/data/config.baseSsm.js b/data/config.baseSsm.js index 23823626..b3521bfa 100644 --- a/data/config.baseSsm.js +++ b/data/config.baseSsm.js @@ -44,6 +44,7 @@ config.settings.contracts.prints = [ 'pdf/ssm.cemetery.burialPermit', 'pdf/ssm.cemetery.contract' ]; +config.settings.printPdf.browser = 'firefox'; config.settings.workOrders.workOrderNumberLength = 6; config.settings.workOrders.workOrderMilestoneDateRecentBeforeDays = 7; config.settings.workOrders.workOrderMilestoneDateRecentAfterDays = 30; diff --git a/data/config.baseSsm.ts b/data/config.baseSsm.ts index 1b730809..7fc6dc4c 100644 --- a/data/config.baseSsm.ts +++ b/data/config.baseSsm.ts @@ -53,6 +53,8 @@ config.settings.contracts.prints = [ 'pdf/ssm.cemetery.contract' ] +config.settings.printPdf.browser = 'firefox' + config.settings.workOrders.workOrderNumberLength = 6 config.settings.workOrders.workOrderMilestoneDateRecentBeforeDays = 7 config.settings.workOrders.workOrderMilestoneDateRecentAfterDays = 30 diff --git a/data/config.defaultValues.d.ts b/data/config.defaultValues.d.ts index 505712b1..8c28a8d7 100644 --- a/data/config.defaultValues.d.ts +++ b/data/config.defaultValues.d.ts @@ -4,11 +4,11 @@ export declare const configDefaultValues: { activeDirectory: ConfigActiveDirectory; 'application.applicationName': string; 'application.backgroundURL': string; - 'application.logoURL': string; 'application.httpPort': number; + 'application.logoURL': string; + 'application.maximumProcesses': number; 'application.userDomain': string; 'application.useTestDatabases': boolean; - 'application.maximumProcesses': number; 'application.ntfyStartup': ConfigNtfyStartup | undefined; 'reverseProxy.disableCompression': boolean; 'reverseProxy.disableEtag': boolean; @@ -22,28 +22,29 @@ export declare const configDefaultValues: { 'users.isAdmin': string[]; 'users.testing': string[]; 'aliases.externalReceiptNumber': string; - 'aliases.workOrderOpenDate': string; 'aliases.workOrderCloseDate': string; + 'aliases.workOrderOpenDate': string; 'settings.cityDefault': string; 'settings.provinceDefault': string; - 'settings.latitudeMin': number; 'settings.latitudeMax': number; - 'settings.longitudeMin': number; + 'settings.latitudeMin': number; 'settings.longitudeMax': number; + 'settings.longitudeMin': number; 'settings.burialSites.burialSiteNameSegments': ConfigBurialSiteNameSegments; 'settings.burialSites.burialSiteNameSegments.includeCemeteryKey': boolean; 'settings.contracts.burialSiteIdIsRequired': boolean; 'settings.contracts.contractEndDateIsRequired': boolean; - 'settings.contracts.purchaserRelationships': string[]; 'settings.contracts.deathAgePeriods': string[]; 'settings.contracts.prints': string[]; + 'settings.contracts.purchaserRelationships': string[]; 'settings.fees.taxPercentageDefault': number; 'settings.workOrders.workOrderNumberLength': number; - 'settings.workOrders.workOrderMilestoneDateRecentBeforeDays': number; - 'settings.workOrders.workOrderMilestoneDateRecentAfterDays': number; 'settings.workOrders.calendarEmailAddress': string; 'settings.workOrders.prints': string[]; + 'settings.workOrders.workOrderMilestoneDateRecentAfterDays': number; + 'settings.workOrders.workOrderMilestoneDateRecentBeforeDays': number; 'settings.adminCleanup.recordDeleteAgeDays': number; + 'settings.printPdf.browser': "chrome" | "firefox"; 'settings.printPdf.contentDisposition': "attachment" | "inline"; 'settings.dynamicsGP.integrationIsEnabled': boolean; 'settings.dynamicsGP.mssqlConfig': MSSQLConfig; diff --git a/data/config.defaultValues.js b/data/config.defaultValues.js index 8b5336f0..14301403 100644 --- a/data/config.defaultValues.js +++ b/data/config.defaultValues.js @@ -3,11 +3,11 @@ export const configDefaultValues = { activeDirectory: undefined, 'application.applicationName': 'Sunrise CMS', 'application.backgroundURL': '/images/cemetery-background.jpg', - 'application.logoURL': '/images/sunrise-cms.svg', 'application.httpPort': 9000, + 'application.logoURL': '/images/sunrise-cms.svg', + 'application.maximumProcesses': 4, 'application.userDomain': '', 'application.useTestDatabases': false, - 'application.maximumProcesses': 4, 'application.ntfyStartup': undefined, 'reverseProxy.disableCompression': false, 'reverseProxy.disableEtag': false, @@ -21,14 +21,14 @@ export const configDefaultValues = { 'users.isAdmin': ['administrator'], 'users.testing': [], 'aliases.externalReceiptNumber': 'External Receipt Number', - 'aliases.workOrderOpenDate': 'Order Date', 'aliases.workOrderCloseDate': 'Completion Date', + 'aliases.workOrderOpenDate': 'Order Date', 'settings.cityDefault': '', 'settings.provinceDefault': '', - 'settings.latitudeMin': -90, 'settings.latitudeMax': 90, - 'settings.longitudeMin': -180, + 'settings.latitudeMin': -90, 'settings.longitudeMax': 180, + 'settings.longitudeMin': -180, 'settings.burialSites.burialSiteNameSegments': { separator: '-', includeCemeteryKey: false, @@ -45,6 +45,13 @@ export const configDefaultValues = { 'settings.burialSites.burialSiteNameSegments.includeCemeteryKey': false, 'settings.contracts.burialSiteIdIsRequired': true, 'settings.contracts.contractEndDateIsRequired': false, + 'settings.contracts.deathAgePeriods': [ + 'Years', + 'Months', + 'Days', + 'Stillborn' + ], + 'settings.contracts.prints': ['screen/contract'], 'settings.contracts.purchaserRelationships': [ 'Spouse', 'Child', @@ -53,20 +60,14 @@ export const configDefaultValues = { 'Friend', 'Self' ], - 'settings.contracts.deathAgePeriods': [ - 'Years', - 'Months', - 'Days', - 'Stillborn' - ], - 'settings.contracts.prints': ['screen/contract'], 'settings.fees.taxPercentageDefault': 0, 'settings.workOrders.workOrderNumberLength': 6, - 'settings.workOrders.workOrderMilestoneDateRecentBeforeDays': 5, - 'settings.workOrders.workOrderMilestoneDateRecentAfterDays': 60, 'settings.workOrders.calendarEmailAddress': 'no-reply@127.0.0.1', 'settings.workOrders.prints': ['pdf/workOrder', 'pdf/workOrder-commentLog'], + 'settings.workOrders.workOrderMilestoneDateRecentAfterDays': 60, + 'settings.workOrders.workOrderMilestoneDateRecentBeforeDays': 5, 'settings.adminCleanup.recordDeleteAgeDays': 60, + 'settings.printPdf.browser': 'chrome', 'settings.printPdf.contentDisposition': 'attachment', 'settings.dynamicsGP.integrationIsEnabled': false, 'settings.dynamicsGP.mssqlConfig': undefined, diff --git a/data/config.defaultValues.ts b/data/config.defaultValues.ts index 7d1a6492..23666d09 100644 --- a/data/config.defaultValues.ts +++ b/data/config.defaultValues.ts @@ -14,11 +14,11 @@ export const configDefaultValues = { 'application.applicationName': 'Sunrise CMS', 'application.backgroundURL': '/images/cemetery-background.jpg', - 'application.logoURL': '/images/sunrise-cms.svg', 'application.httpPort': 9000, + 'application.logoURL': '/images/sunrise-cms.svg', + 'application.maximumProcesses': 4, 'application.userDomain': '', 'application.useTestDatabases': false, - 'application.maximumProcesses': 4, 'application.ntfyStartup': undefined as ConfigNtfyStartup | undefined, @@ -37,16 +37,16 @@ export const configDefaultValues = { 'users.testing': [] as string[], 'aliases.externalReceiptNumber': 'External Receipt Number', - 'aliases.workOrderOpenDate': 'Order Date', 'aliases.workOrderCloseDate': 'Completion Date', + 'aliases.workOrderOpenDate': 'Order Date', 'settings.cityDefault': '', 'settings.provinceDefault': '', - 'settings.latitudeMin': -90, 'settings.latitudeMax': 90, - 'settings.longitudeMin': -180, + 'settings.latitudeMin': -90, 'settings.longitudeMax': 180, + 'settings.longitudeMin': -180, 'settings.burialSites.burialSiteNameSegments': { separator: '-', @@ -66,6 +66,13 @@ export const configDefaultValues = { 'settings.contracts.burialSiteIdIsRequired': true, 'settings.contracts.contractEndDateIsRequired': false, + 'settings.contracts.deathAgePeriods': [ + 'Years', + 'Months', + 'Days', + 'Stillborn' + ], + 'settings.contracts.prints': ['screen/contract'], 'settings.contracts.purchaserRelationships': [ 'Spouse', 'Child', @@ -74,25 +81,19 @@ export const configDefaultValues = { 'Friend', 'Self' ], - 'settings.contracts.deathAgePeriods': [ - 'Years', - 'Months', - 'Days', - 'Stillborn' - ], - 'settings.contracts.prints': ['screen/contract'], 'settings.fees.taxPercentageDefault': 0, 'settings.workOrders.workOrderNumberLength': 6, - 'settings.workOrders.workOrderMilestoneDateRecentBeforeDays': 5, - 'settings.workOrders.workOrderMilestoneDateRecentAfterDays': 60, 'settings.workOrders.calendarEmailAddress': 'no-reply@127.0.0.1', 'settings.workOrders.prints': ['pdf/workOrder', 'pdf/workOrder-commentLog'], + 'settings.workOrders.workOrderMilestoneDateRecentAfterDays': 60, + 'settings.workOrders.workOrderMilestoneDateRecentBeforeDays': 5, 'settings.adminCleanup.recordDeleteAgeDays': 60, + 'settings.printPdf.browser': 'chrome' as 'chrome' | 'firefox', 'settings.printPdf.contentDisposition': 'attachment' as | 'attachment' | 'inline', diff --git a/handlers/print-get/pdf.js b/handlers/print-get/pdf.js index 3b80f3e6..867dac6c 100644 --- a/handlers/print-get/pdf.js +++ b/handlers/print-get/pdf.js @@ -34,6 +34,8 @@ export async function handler(request, response, next) { format: 'letter', printBackground: true, preferCSSPageSize: true + }, { + usePackagePuppeteer: true }); pdfCallbackFunction(Buffer.from(pdf)); } diff --git a/handlers/print-get/pdf.ts b/handlers/print-get/pdf.ts index 550f660e..3ef8d6f1 100644 --- a/handlers/print-get/pdf.ts +++ b/handlers/print-get/pdf.ts @@ -76,6 +76,8 @@ export async function handler( format: 'letter', printBackground: true, preferCSSPageSize: true + }, { + usePackagePuppeteer: true }) pdfCallbackFunction(Buffer.from(pdf)) diff --git a/package-lock.json b/package-lock.json index f80efa4f..b8678efb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@cityssm/dynamics-gp": "^1.1.0", "@cityssm/fa-glow": "^0.1.0", "@cityssm/ntfy-publish": "^1.1.0", - "@cityssm/pdf-puppeteer": "^4.4.0", + "@cityssm/pdf-puppeteer": "^5.0.0", "@cityssm/utils-datetime": "^1.3.0", "@fortawesome/fontawesome-free": "^6.7.2", "activedirectory2": "^2.2.0", @@ -39,6 +39,7 @@ "leaflet": "^1.9.4", "node-cache": "^5.1.2", "papaparse": "^5.5.2", + "puppeteer": "^19.4.1", "randomcolor": "^0.6.2", "session-file-store": "^1.5.0", "set-interval-async": "^3.0.3" @@ -465,9 +466,9 @@ "license": "MIT" }, "node_modules/@cityssm/pdf-puppeteer": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@cityssm/pdf-puppeteer/-/pdf-puppeteer-4.4.0.tgz", - "integrity": "sha512-eKqUJfvEWxZFE20PYx8oErwJSI8569BZiTz/g4GfsdWEQykGh/OmHVRfObegpKsnpxV+dVl0rUx+tuk1egG/eA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@cityssm/pdf-puppeteer/-/pdf-puppeteer-5.0.0.tgz", + "integrity": "sha512-kN3GGA58LAtU8ArRmgkhWIdPvL0La4vIDwyIReQOHZ4kCvk9PvneG5akg/BH5L4Mb+nq6aaDtwHrrWc1fhSlaA==", "license": "MIT", "dependencies": { "@cityssm/paper-sizes": "^1.0.1", @@ -494,6 +495,106 @@ "node": ">=18.0.0" } }, + "node_modules/@cityssm/puppeteer-launch/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@cityssm/puppeteer-launch/node_modules/devtools-protocol": { + "version": "0.0.1413902", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1413902.tgz", + "integrity": "sha512-yRtvFD8Oyk7C9Os3GmnFZLu53yAfsnyw1s+mLmHHUK0GQEc9zthHWvS1r67Zqzm5t7v56PILHIVZ7kmFMaL2yQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@cityssm/puppeteer-launch/node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@cityssm/puppeteer-launch/node_modules/puppeteer": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.4.0.tgz", + "integrity": "sha512-E4JhJzjS8AAI+6N/b+Utwarhz6zWl3+MR725fal+s3UlOlX2eWdsvYYU+Q5bXMjs9eZEGkNQroLkn7j11s2k1Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.8.0", + "chromium-bidi": "2.1.2", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1413902", + "puppeteer-core": "24.4.0", + "typed-query-selector": "^2.12.0" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cityssm/puppeteer-launch/node_modules/puppeteer-core": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.4.0.tgz", + "integrity": "sha512-eFw66gCnWo0X8Hyf9KxxJtms7a61NJVMiSaWfItsFPzFBsjsWdmcNlBdsA1WVwln6neoHhsG+uTVesKmTREn/g==", + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.8.0", + "chromium-bidi": "2.1.2", + "debug": "^4.4.0", + "devtools-protocol": "0.0.1413902", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cityssm/puppeteer-launch/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@cityssm/simple-fa5-checkbox": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@cityssm/simple-fa5-checkbox/-/simple-fa5-checkbox-0.2.1.tgz", @@ -1637,16 +1738,16 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.7.1.tgz", - "integrity": "sha512-MK7rtm8JjaxPN7Mf1JdZIZKPD2Z+W7osvrC1vjpvfOX1K0awDIHYbNi89f7eotp7eMUn2shWnt03HwVbriXtKQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.8.0.tgz", + "integrity": "sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ==", "license": "Apache-2.0", "dependencies": { "debug": "^4.4.0", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", - "semver": "^7.7.0", + "semver": "^7.7.1", "tar-fs": "^3.0.8", "yargs": "^17.7.2" }, @@ -2815,9 +2916,10 @@ } }, "node_modules/b4a": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", - "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "license": "Apache-2.0" }, "node_modules/backoff": { "version": "2.5.0", @@ -2841,34 +2943,43 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/bare-events": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", - "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "license": "Apache-2.0", "optional": true }, "node_modules/bare-fs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.1.tgz", - "integrity": "sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.2.tgz", + "integrity": "sha512-S5mmkMesiduMqnz51Bfh0Et9EX0aTCJxhsI4bvzFFLs8Z1AV8RDHadfY5CyLwdoLHgXbNBEN1gQcbEtGwuvixw==", "license": "Apache-2.0", "optional": true, "dependencies": { - "bare-events": "^2.0.0", + "bare-events": "^2.5.4", "bare-path": "^3.0.0", - "bare-stream": "^2.0.0" + "bare-stream": "^2.6.4" }, "engines": { - "bare": ">=1.7.0" + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } } }, "node_modules/bare-os": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.4.0.tgz", - "integrity": "sha512-9Ous7UlnKbe3fMi7Y+qh0DwAup6A1JkYgPnjvMDNOlmnxNRQvQ/7Nst+OnUQKzk0iAT0m9BisbDVp9gCv8+ETA==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", + "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", "license": "Apache-2.0", "optional": true, "engines": { - "bare": ">=1.6.0" + "bare": ">=1.14.0" } }, "node_modules/bare-path": { @@ -3422,9 +3533,9 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "node_modules/chromium-bidi": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-1.2.0.tgz", - "integrity": "sha512-XtdJ1GSN6S3l7tO7F77GhNsw0K367p0IsLYf2yZawCVAKKC3lUvDhPdMVrB2FNhmhfW43QGYbEX3Wg6q0maGwQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-2.1.2.tgz", + "integrity": "sha512-vtRWBK2uImo5/W2oG6/cDkkHSm+2t6VHgnj+Rcwhb0pP74OoUb4GipyRX/T/y39gYQPhioP0DPShn+A7P6CHNw==", "license": "Apache-2.0", "dependencies": { "mitt": "^3.0.1", @@ -3828,38 +3939,18 @@ "license": "MIT" }, "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", + "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", "license": "MIT", "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", + "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" + "parse-json": "^5.0.0", + "path-type": "^4.0.0" }, "engines": { "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cosmiconfig/node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "license": "MIT", - "engines": { - "node": ">=6" } }, "node_modules/cross-env": { @@ -3879,6 +3970,15 @@ "yarn": ">=1" } }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "license": "MIT", + "dependencies": { + "node-fetch": "2.6.7" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4457,9 +4557,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1402036", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1402036.tgz", - "integrity": "sha512-JwAYQgEvm3yD45CHB+RmF5kMbWtXBaOGwuxa87sZogHcLCv8c/IqnThaoQ1y60d7pXWjSKWQphPEc+1rAScVdg==", + "version": "0.0.1068969", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1068969.tgz", + "integrity": "sha512-ATFTrPbY1dKYhPPvpjtwWKSK2mIwGmRwX54UASn9THEuIZCe2n9k3vVuMmt6jWeL+e5QaaguEv/pMyR+JQB7VQ==", "license": "BSD-3-Clause" }, "node_modules/doctrine": { @@ -5886,7 +5986,8 @@ "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", @@ -9255,6 +9356,26 @@ "node": ">= 8.0.0" } }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-gyp-build": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", @@ -9737,9 +9858,9 @@ } }, "node_modules/pac-proxy-agent": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz", - "integrity": "sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", "license": "MIT", "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", @@ -9872,6 +9993,15 @@ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/pe-coff": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/pe-coff/-/pe-coff-1.0.0.tgz", @@ -10186,43 +10316,129 @@ } }, "node_modules/puppeteer": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.2.0.tgz", - "integrity": "sha512-z8vv7zPEgrilIbOo3WNvM+2mXMnyM9f4z6zdrB88Fzeuo43Oupmjrzk3EpuvuCtyK0A7Lsllfx7Z+4BvEEGJcQ==", + "version": "19.4.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.4.1.tgz", + "integrity": "sha512-PCnrR13B8A+VSEDXRmrNXRZbrkF1tfsI1hKSC7vs13eNS6CUD3Y4FA8SF8/VZy+Pm1kg5AggJT2Nu3HLAtGkFg==", + "deprecated": "< 22.8.2 is no longer supported", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.7.1", - "chromium-bidi": "1.2.0", - "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1402036", - "puppeteer-core": "24.2.0", - "typed-query-selector": "^2.12.0" - }, - "bin": { - "puppeteer": "lib/cjs/puppeteer/node/cli.js" + "cosmiconfig": "8.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "puppeteer-core": "19.4.1" }, "engines": { - "node": ">=18" + "node": ">=14.1.0" } }, "node_modules/puppeteer-core": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.2.0.tgz", - "integrity": "sha512-e4A4/xqWdd4kcE6QVHYhJ+Qlx/+XpgjP4d8OwBx0DJoY/nkIRhSgYmKQnv7+XSs1ofBstalt+XPGrkaz4FoXOQ==", + "version": "19.4.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.4.1.tgz", + "integrity": "sha512-JHIuqtqrUAx4jGOTxXu4ilapV2jabxtVMA/e4wwFUMvtSsqK4nVBSI+Z1SKDoz7gRy/JUIc8WzmfocCa6SIZ1w==", "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.7.1", - "chromium-bidi": "1.2.0", - "debug": "^4.4.0", - "devtools-protocol": "0.0.1402036", - "typed-query-selector": "^2.12.0", - "ws": "^8.18.0" + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.1068969", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.11.0" }, "engines": { - "node": ">=18" + "node": ">=14.1.0" } }, + "node_modules/puppeteer-core/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/puppeteer-core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/puppeteer-core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/puppeteer-core/node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/puppeteer/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/puppeteer/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/puppeteer/node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -10738,6 +10954,22 @@ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rndm": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", @@ -11247,9 +11479,9 @@ } }, "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", "license": "MIT", "dependencies": { "ip-address": "^9.0.5", @@ -11776,9 +12008,10 @@ } }, "node_modules/text-decoder": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", - "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" } @@ -11792,8 +12025,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "node_modules/tldts": { "version": "6.1.85", @@ -11880,6 +12112,12 @@ "node": ">=16" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -12157,6 +12395,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "license": "MIT", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -12415,6 +12663,22 @@ "dev": true, "license": "MIT" }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -12651,16 +12915,16 @@ "license": "MIT" }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "utf-8-validate": "^5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -12768,9 +13032,9 @@ } }, "node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index ec737d6b..e11f812f 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@cityssm/dynamics-gp": "^1.1.0", "@cityssm/fa-glow": "^0.1.0", "@cityssm/ntfy-publish": "^1.1.0", - "@cityssm/pdf-puppeteer": "^4.4.0", + "@cityssm/pdf-puppeteer": "^5.0.0", "@cityssm/utils-datetime": "^1.3.0", "@fortawesome/fontawesome-free": "^6.7.2", "activedirectory2": "^2.2.0", @@ -62,6 +62,7 @@ "leaflet": "^1.9.4", "node-cache": "^5.1.2", "papaparse": "^5.5.2", + "puppeteer": "^19.4.1", "randomcolor": "^0.6.2", "session-file-store": "^1.5.0", "set-interval-async": "^3.0.3" diff --git a/types/configTypes.d.ts b/types/configTypes.d.ts index f34c82d4..10257cfb 100644 --- a/types/configTypes.d.ts +++ b/types/configTypes.d.ts @@ -50,6 +50,7 @@ export interface Config { recordDeleteAgeDays?: number; }; printPdf: { + browser?: 'chrome' | 'firefox'; contentDisposition?: 'attachment' | 'inline'; }; dynamicsGP?: { diff --git a/types/configTypes.ts b/types/configTypes.ts index 377aa82f..5398cc10 100644 --- a/types/configTypes.ts +++ b/types/configTypes.ts @@ -65,6 +65,7 @@ export interface Config { } printPdf: { + browser?: 'chrome' | 'firefox', contentDisposition?: 'attachment' | 'inline' } diff --git a/views/login.ejs b/views/login.ejs index 289e640f..d6cc2146 100644 --- a/views/login.ejs +++ b/views/login.ejs @@ -25,68 +25,74 @@ " alt="" style="max-height:400px" />
-

+

<%= configFunctions.getConfigProperty("application.applicationName") %> -

-
- - + + + + -
-
- <%= configFunctions.getConfigProperty("application.userDomain") %>\ -
-
- -
+
+
+ <%= configFunctions.getConfigProperty("application.userDomain") %>\
-
- -
- - - - -
+
+
- <% if (useTestDatabases) { %> -
-

- Testing databases in use! -

-
- <% } %> -
-
- <% if (message !== "") { %> - - - - <%= message %> - <% } %> -
-
- -
-
- -
-
- Build <%= buildNumber %>
- - - Help - - - - GitHub -
+
+ +
+ + + + +
+
+ <% if (useTestDatabases) { %> +
+

+ Testing databases in use! +

+
+ <% } %> +
+
+ <% if (message !== "") { %> + + + + <%= message %> + <% } %> +
+
+ +
+
+ +
+

+ Build <%= buildNumber %> +

+

+ + + + + Help + + + + + + GitHub + +

@@ -97,8 +103,8 @@ - + \ No newline at end of file