diff --git a/gatsby-node.js b/gatsby-node.js index 857a6cfed..25152db7b 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -4,4 +4,14 @@ * See: https://www.gatsbyjs.org/docs/node-apis/ */ -// You can delete this file if you're not using it \ No newline at end of file +// You can delete this file if you're not using it + +exports.onCreateWebpackConfig = ({ stage, actions }) => { + actions.setWebpackConfig({ + + //allow us to not use ENVIRONMENT=web when compiling anypia-js, test it + // https://stackoverflow.com/questions/59487224/webpack-throws-error-with-emscripten-cant-resolve-fs + "node": { "fs": "empty" }, + "resolve": { fallback: { "path": false, "fs": false, "crypto": false } } + }) + } diff --git a/package-lock.json b/package-lock.json index 0473c00c5..fdbd09015 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "windfall-awareness", "version": "0.5.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, "packages": { "": { @@ -43127,6 +43127,14 @@ "define-properties": "^1.1.3" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, "stringify-entities": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz", diff --git a/src/library/anypiajs.mjs b/src/library/anypiajs.mjs index 472f0635e..23f188b6c 100644 --- a/src/library/anypiajs.mjs +++ b/src/library/anypiajs.mjs @@ -10,7 +10,7 @@ import 'core-js/modules/es6.typed-array.uint8-clamped-array' // See: https://stackoverflow.com/questions/63592691/core-js-cannot-resolve-core-js-modules-es6-typed-uint32-array/63592692#63592692 var Module = (function() { - var _scriptDir = '/anypiajs.wasm'; + var _scriptDir = '/anypiajs-20211-versioned2.wasm'; return ( function(Module) { @@ -18,6 +18,8 @@ function(Module) { + + // The Module object: Our interface to the outside world. We import // and export values on it. There are various ways Module can be used: // 1. Not defined. We create it here @@ -193,10 +195,16 @@ var quit_ = function(status, toThrow) { // Determine the runtime environment we are in. You can customize this by // setting the ENVIRONMENT setting at compile time (see settings.js). -var ENVIRONMENT_IS_WEB = true; +var ENVIRONMENT_IS_WEB = false; var ENVIRONMENT_IS_WORKER = false; var ENVIRONMENT_IS_NODE = false; var ENVIRONMENT_IS_SHELL = false; +ENVIRONMENT_IS_WEB = typeof window === 'object'; +ENVIRONMENT_IS_WORKER = typeof importScripts === 'function'; +// N.b. Electron.js environment is simultaneously a NODE-environment, but +// also a web environment. +ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string'; +ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; if (Module['ENVIRONMENT']) { throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)'); @@ -219,6 +227,104 @@ var read_, readBinary, setWindowTitle; +var nodeFS; +var nodePath; + +if (ENVIRONMENT_IS_NODE) { + if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = require('path').dirname(scriptDirectory) + '/'; + } else { + scriptDirectory = __dirname + '/'; + } + + + + + read_ = function shell_read(filename, binary) { + if (!nodeFS) nodeFS = require('fs'); + if (!nodePath) nodePath = require('path'); + filename = nodePath['normalize'](filename); + return nodeFS['readFileSync'](filename, binary ? null : 'utf8'); + }; + + readBinary = function readBinary(filename) { + var ret = read_(filename, true); + if (!ret.buffer) { + ret = new Uint8Array(ret); + } + assert(ret.buffer); + return ret; + }; + + + + + if (process['argv'].length > 1) { + thisProgram = process['argv'][1].replace(/\\/g, '/'); + } + + arguments_ = process['argv'].slice(2); + + // MODULARIZE will export the module in the proper place outside, we don't need to export here + + process['on']('uncaughtException', function(ex) { + // suppress ExitStatus exceptions from showing an error + if (!(ex instanceof ExitStatus)) { + throw ex; + } + }); + + process['on']('unhandledRejection', abort); + + quit_ = function(status) { + process['exit'](status); + }; + + Module['inspect'] = function () { return '[Emscripten Module object]'; }; + + + +} else +if (ENVIRONMENT_IS_SHELL) { + + + if (typeof read != 'undefined') { + read_ = function shell_read(f) { + return read(f); + }; + } + + readBinary = function readBinary(f) { + var data; + if (typeof readbuffer === 'function') { + return new Uint8Array(readbuffer(f)); + } + data = read(f, 'binary'); + assert(typeof data === 'object'); + return data; + }; + + if (typeof scriptArgs != 'undefined') { + arguments_ = scriptArgs; + } else if (typeof arguments != 'undefined') { + arguments_ = arguments; + } + + if (typeof quit === 'function') { + quit_ = function(status) { + quit(status); + }; + } + + if (typeof print !== 'undefined') { + // Prefer to use print/printErr where they exist, as they usually work better. + if (typeof console === 'undefined') console = /** @type{!Console} */({}); + console.log = /** @type{!function(this:Console, ...*): undefined} */ (print); + console.warn = console.error = /** @type{!function(this:Console, ...*): undefined} */ (typeof printErr !== 'undefined' ? printErr : print); + } + + +} else // Note that this includes Node.js workers when relevant (pthreads is enabled). // Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and @@ -244,7 +350,6 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { scriptDirectory = ''; } - if (!(typeof window === 'object' || typeof importScripts === 'function')) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); // Differentiate the Web Worker from the Node Worker case, as reading must // be done differently. @@ -1359,11 +1464,11 @@ function updateGlobalBufferAndViews(buf) { } var STATIC_BASE = 1024, - STACK_BASE = 74208, + STACK_BASE = 74512, STACKTOP = STACK_BASE, - STACK_MAX = 5317088, - DYNAMIC_BASE = 5317088, - DYNAMICTOP_PTR = 74000; + STACK_MAX = 5317392, + DYNAMIC_BASE = 5317392, + DYNAMICTOP_PTR = 74304; assert(STACK_BASE % 16 === 0, 'stack must start aligned'); assert(DYNAMIC_BASE % 16 === 0, 'heap must start aligned'); @@ -1787,7 +1892,7 @@ function createExportWrapper(name, fixedasm) { }; } -var wasmBinaryFile = 'anypiajs.wasm'; +var wasmBinaryFile = 'anypiajs-20211-versioned2.wasm'; if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(wasmBinaryFile); } @@ -1813,6 +1918,8 @@ function getBinaryPromise() { // If we don't have the binary yet, and have the Fetch api, use that; // in some environments, like Electron's render process, Fetch api may be present, but have a different context than expected, let's only use it on the Web if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === 'function' + // Let's not use fetch to get objects over file:// as it's most likely Cordova which doesn't support fetch for file:// + && !isFileURI(wasmBinaryFile) ) { return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) { if (!response['ok']) { @@ -1890,6 +1997,8 @@ function createWasm() { if (!wasmBinary && typeof WebAssembly.instantiateStreaming === 'function' && !isDataURI(wasmBinaryFile) && + // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously. + !isFileURI(wasmBinaryFile) && typeof fetch === 'function') { fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function (response) { var result = WebAssembly.instantiateStreaming(response, info); @@ -1936,7 +2045,7 @@ var ASM_CONSTS = []; -// STATICTOP = STATIC_BASE + 73184; +// STATICTOP = STATIC_BASE + 73488; /* global initializers */ __ATINIT__.push({ func: function() { globalCtors() } }); @@ -1947,7 +2056,7 @@ var ASM_CONSTS = []; /* no memory initializer */ -var tempDoublePtr = 74192; +var tempDoublePtr = 74496; function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much HEAP8[tempDoublePtr] = HEAP8[ptr]; @@ -2290,6 +2399,27 @@ function copyTempDouble(ptr) { }},default_tty_ops:{get_char:function(tty) { if (!tty.input.length) { var result = null; + if (ENVIRONMENT_IS_NODE) { + // we will read data by chunks of BUFSIZE + var BUFSIZE = 256; + var buf = Buffer.alloc ? Buffer.alloc(BUFSIZE) : new Buffer(BUFSIZE); + var bytesRead = 0; + + try { + bytesRead = nodeFS.readSync(process.stdin.fd, buf, 0, BUFSIZE, null); + } catch(e) { + // Cross-platform differences: on Windows, reading EOF throws an exception, but on other OSes, + // reading EOF returns 0. Uniformize behavior by treating the EOF exception to return 0. + if (e.toString().indexOf('EOF') != -1) bytesRead = 0; + else throw e; + } + + if (bytesRead > 0) { + result = buf.slice(0, bytesRead).toString('utf-8'); + } else { + result = null; + } + } else if (typeof window != 'undefined' && typeof window.prompt == 'function') { // Browser. @@ -3735,6 +3865,16 @@ function copyTempDouble(ptr) { var randomBuffer = new Uint8Array(1); random_device = function() { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; }; } else + if (ENVIRONMENT_IS_NODE) { + // for nodejs with or without crypto support included + try { + var crypto_module = require('crypto'); + // nodejs has crypto support + random_device = function() { return crypto_module['randomBytes'](1)[0]; }; + } catch (e) { + // nodejs doesn't have crypto support + } + } else {} if (!random_device) { // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096 @@ -6206,7 +6346,7 @@ function copyTempDouble(ptr) { } - var ___tm_timezone=(stringToUTF8("GMT", 74096, 4), 74096); + var ___tm_timezone=(stringToUTF8("GMT", 74400, 4), 74400); function _tzset() { // TODO: Use (malleable) environment variables instead of system settings. @@ -6947,8 +7087,8 @@ var dynCall_viiiiii = Module["dynCall_viiiiii"] = createExportWrapper("dynCall_v /** @type {function(...*):?} */ var dynCall_viijii = Module["dynCall_viijii"] = createExportWrapper("dynCall_viijii"); -Module['__ZZNKSt3__27num_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEE6do_putES4_RNS_8ios_baseEwPKvE5__fmt'] = 62561; -Module['__ZZNKSt3__27num_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEE6do_putES4_RNS_8ios_baseEwmE5__fmt'] = 62572;; +Module['__ZZNKSt3__27num_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEE6do_putES4_RNS_8ios_baseEwPKvE5__fmt'] = 62863; +Module['__ZZNKSt3__27num_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEE6do_putES4_RNS_8ios_baseEwmE5__fmt'] = 62874;; @@ -6974,7 +7114,7 @@ if (!Object.getOwnPropertyDescriptor(Module, "addOnPreRun")) Module["addOnPreRun if (!Object.getOwnPropertyDescriptor(Module, "addOnInit")) Module["addOnInit"] = function() { abort("'addOnInit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "addOnPreMain")) Module["addOnPreMain"] = function() { abort("'addOnPreMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "addOnExit")) Module["addOnExit"] = function() { abort("'addOnExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; -if (!Object.getOwnPropertyDescriptor(Module, "addOnPostRun")) Module["addOnPostRun"] = function() { abort("'addOnPostRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; +Module["addOnPostRun"] = addOnPostRun; if (!Object.getOwnPropertyDescriptor(Module, "writeStringToMemory")) Module["writeStringToMemory"] = function() { abort("'writeStringToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "writeArrayToMemory")) Module["writeArrayToMemory"] = function() { abort("'writeArrayToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; if (!Object.getOwnPropertyDescriptor(Module, "writeAsciiToMemory")) Module["writeAsciiToMemory"] = function() { abort("'writeAsciiToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; diff --git a/src/library/pia/index.ts b/src/library/pia/index.ts index 017854ac2..248ec27b3 100644 --- a/src/library/pia/index.ts +++ b/src/library/pia/index.ts @@ -193,7 +193,8 @@ export async function finalCalculation( aime: calculation.AIME && calculation.AIME.AME, fullRetireDate: new Date("2040-1-1").toLocaleDateString("en-US"), calculatorType: 'anypia', - bendPoints: usePIAAfterWindwfall ? calculation.PIAAfterWindwfall : calculation.PIAEligibility + bendPoints: usePIAAfterWindwfall ? calculation.PIAAfterWindwfall : calculation.PIAEligibility, + calculatorApp: resultObj.App }; console.log("usePIAAfterWindwfall", usePIAAfterWindwfall); console.warn("DUMMY fullRetireDate until it can be added:"); diff --git a/src/library/user-state-context.tsx b/src/library/user-state-context.tsx index 14d15f007..097aaa3fe 100644 --- a/src/library/user-state-context.tsx +++ b/src/library/user-state-context.tsx @@ -42,6 +42,12 @@ interface BendPoints { // HIGH = "HIGH", // } +export interface CalculatorApp { + Description: string; + Name: string; + Version: string; +} + // Calculated results for the user export interface UserProfile { "Standard PIA": string; @@ -54,6 +60,7 @@ export interface UserProfile { fullRetireDate: string; calculatorType: string; bendPoints?: BendPoints[] + calculatorApp?: CalculatorApp; } export interface UserState { diff --git a/src/pages/screen-2.tsx b/src/pages/screen-2.tsx index 17b5ba251..6b2434d9c 100644 --- a/src/pages/screen-2.tsx +++ b/src/pages/screen-2.tsx @@ -54,6 +54,10 @@ const Text = styled.div` font-size: ${fontSizes[1]}; `; +const GlossaryContainer = styled.div` + margin-left: 20px; +`; + interface Screen2Props { userState: UserState; userStateActions: UserStateActions; @@ -383,20 +387,15 @@ export class Screen2 extends React.Component { ) : null} {preferPiaUserCalc && ( - -
- - The current version of the Social Security Detailed - Calculator is 2020.1, which was released on December 31, - 2019. It updates the 2019.2 version with the new economic - information from the automatic adjustments announced on - October 10, 2019. - -
+ + + {userProfile.calculatorApp?.Description} + + )} diff --git a/src/test/pia-index.test.ts b/src/test/pia-index.test.ts index a53b5786d..2039917e5 100644 --- a/src/test/pia-index.test.ts +++ b/src/test/pia-index.test.ts @@ -1,28 +1,49 @@ // TODO ENABLE NODEJS mode for Emscripten Module and uncomment this file // will not work without this. Also need to find way to reference wasm file for tests since /anypiajs.wasm won't workA -// import { finalCalculation } from "../library/pia/index"; -// import { delayedRetirementValues, fullRetirementValues, sample20RetirementValues } from "../library/testFiles"; -// import { -// finalCalculation as originalFinalCalculation, -// getRawEarnings, -// } from "../library/observable-functions"; +import { finalCalculation } from "../library/pia/index"; +import { delayedRetirementValues, fullRetirementValues, sample20RetirementValues } from "../library/testFiles"; +import { + finalCalculation as originalFinalCalculation, + getRawEarnings, +} from "../library/observable-functions"; +import dayjs from "dayjs"; + + describe("Run AnyPIAJS", () => { - it("once it is recompiled with NodeJS support", async () => { + it("Now it has NodeJS support", async () => { expect.assertions(1); expect(null).toBe(null); }); }); - +// TODO: try to get the below block running soon. +// Do an approach like this: https://github.com/emscripten-core/emscripten/issues/8400#issuecomment-498218291 // describe("John Q. Public (Full Retirement)", async () => { + +// beforeAll(async () => { +// var loader = ???(); +// loader.ready = () => +// // https://github.com/emscripten-core/emscripten/issues/5820 +// new Promise((resolve, reject) => { +// delete loader.then; +// loader.onAbort = reject; +// loader.addOnPostRun(() => { +// resolve(loader); +// }); +// }); +// ??? = await loader.ready(); +// }); + // const earnings = // fullRetirementValues["osss:OnlineSocialSecurityStatementData"][ // "osss:EarningsRecord" // ]["osss:Earnings"]; -// const userDOB = new Date("1947-10-10"); -// const userDOR = new Date("2013-10-10"); // 66 is their full retirement age + +// const userDOB = "1947-10-10"; +// const userDOR = dayjs("2013-10-10").toDate(); // 66yo is their full retirement age. +// //const year62 = "2014"; // const rawEarnings = getRawEarnings(earnings); // const userPension = 0; @@ -30,7 +51,10 @@ describe("Run AnyPIAJS", () => { // userDOB, // userDOR, // userPension, -// rawEarnings +// rawEarnings, +// null, +// null, +// null,null // ); // // var userCalc = await finalCalculation(userDOB, userDOR, year62, userYSE, userPension, userAIME) @@ -41,7 +65,9 @@ describe("Run AnyPIAJS", () => { // expect(userYSE).toBe(30); // }); +// }); +////====TESTS FOR LATER, or removal===== // it("Correctly calculates AIME from a full earnings record.", async () => { // expect.assertions(1); diff --git a/static/anypiajs-20201.wasm b/static/anypiajs-20201.wasm new file mode 100644 index 000000000..c001b78dd Binary files /dev/null and b/static/anypiajs-20201.wasm differ diff --git a/static/anypiajs-20211-versioned2.wasm b/static/anypiajs-20211-versioned2.wasm new file mode 100644 index 000000000..e9026eb0f Binary files /dev/null and b/static/anypiajs-20211-versioned2.wasm differ