From 3dfac7e4b061b0a239c3f75bfe8e6feb122fe669 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:30:36 +0000 Subject: [PATCH 1/5] Initial plan From 3c6c9d9bb93c8c68dbdc84ae275944c7e4f48392 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:37:12 +0000 Subject: [PATCH 2/5] =?UTF-8?q?Add=20scientific=20operations=20to=20the=20?= =?UTF-8?q?Palant=C3=ADr:=20power,=20sqrt,=20sin,=20cos,=20tan,=20log,=20l?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: haslam93 <36418598+haslam93@users.noreply.github.com> --- api/controller.js | 22 +++++++++++---- test/arithmetic.test.js | 59 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/api/controller.js b/api/controller.js index 949731c..a3acfc1 100644 --- a/api/controller.js +++ b/api/controller.js @@ -16,8 +16,17 @@ exports.calculate = function(req, res) { 'subtract': function(a, b) { return a - b }, 'multiply': function(a, b) { return a * b }, 'divide': function(a, b) { return a / b }, + 'power': function(a, b) { return Math.pow(a, b) }, + 'sqrt': function(a) { return Math.sqrt(a) }, + 'sin': function(a) { return Math.sin(a) }, + 'cos': function(a) { return Math.cos(a) }, + 'tan': function(a) { return Math.tan(a) }, + 'log': function(a) { return Math.log10(a) }, + 'ln': function(a) { return Math.log(a) }, }; + var singleOperandOps = ['sqrt', 'sin', 'cos', 'tan', 'log', 'ln']; + if (!req.query.operation) { throw new Error("Unspecified operation"); } @@ -29,15 +38,18 @@ exports.calculate = function(req, res) { } if (!req.query.operand1 || - !req.query.operand1.match(/^(-)?[0-9\.]+(e(-)?[0-9]+)?$/) || + !req.query.operand1.match(/^(-)?[0-9.]+(e(-)?[0-9]+)?$/) || req.query.operand1.replace(/[-0-9e]/g, '').length > 1) { throw new Error("Invalid operand1: " + req.query.operand1); } - if (!req.query.operand2 || - !req.query.operand2.match(/^(-)?[0-9\.]+(e(-)?[0-9]+)?$/) || - req.query.operand2.replace(/[-0-9e]/g, '').length > 1) { - throw new Error("Invalid operand2: " + req.query.operand2); + // Only validate operand2 for operations that require two operands + if (!singleOperandOps.includes(req.query.operation)) { + if (!req.query.operand2 || + !req.query.operand2.match(/^(-)?[0-9.]+(e(-)?[0-9]+)?$/) || + req.query.operand2.replace(/[-0-9e]/g, '').length > 1) { + throw new Error("Invalid operand2: " + req.query.operand2); + } } res.json({ result: operation(req.query.operand1, req.query.operand2) }); diff --git a/test/arithmetic.test.js b/test/arithmetic.test.js index deded48..961b226 100644 --- a/test/arithmetic.test.js +++ b/test/arithmetic.test.js @@ -205,4 +205,63 @@ describe('Arithmetic', function () { }); }); }); + + describe('Scientific Operations - Power of the Istari', function () { + it('raises number to power', function (done) { + request.get('/arithmetic?operation=power&operand1=2&operand2=3') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 8 }); + done(); + }); + }); + it('calculates square root', function (done) { + request.get('/arithmetic?operation=sqrt&operand1=9') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 3 }); + done(); + }); + }); + it('calculates sine of zero', function (done) { + request.get('/arithmetic?operation=sin&operand1=0') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 0 }); + done(); + }); + }); + it('calculates cosine of zero', function (done) { + request.get('/arithmetic?operation=cos&operand1=0') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 1 }); + done(); + }); + }); + it('calculates tangent of zero', function (done) { + request.get('/arithmetic?operation=tan&operand1=0') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 0 }); + done(); + }); + }); + it('calculates log10 of 100', function (done) { + request.get('/arithmetic?operation=log&operand1=100') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 2 }); + done(); + }); + }); + it('calculates natural log of e', function (done) { + request.get('/arithmetic?operation=ln&operand1=2.718281828459045') + .expect(200) + .end(function (err, res) { + expect(res.body.result).to.be.closeTo(1, 0.0001); + done(); + }); + }); + }); }); From fe56f414f600fffe76dbae64466b8191e201cb65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:42:22 +0000 Subject: [PATCH 3/5] =?UTF-8?q?Forge=20the=20UI=20of=20the=20Scientific=20?= =?UTF-8?q?Palant=C3=ADr=20with=20all=20scientific=20buttons=20and=20funct?= =?UTF-8?q?ions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: haslam93 <36418598+haslam93@users.noreply.github.com> --- public/client.js | 38 +++++++++++++++++++++++++++++++++++++- public/default.css | 14 ++++++++++++++ public/index.html | 19 ++++++++++++++----- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/public/client.js b/public/client.js index 1d21fd9..737ab62 100644 --- a/public/client.js +++ b/public/client.js @@ -33,13 +33,39 @@ function calculate(operand1, operand2, operation) { case '/': uri += "?operation=divide"; break; + case '^': + uri += "?operation=power"; + break; + case '√': + uri += "?operation=sqrt"; + break; + case 'sin': + uri += "?operation=sin"; + break; + case 'cos': + uri += "?operation=cos"; + break; + case 'tan': + uri += "?operation=tan"; + break; + case 'log': + uri += "?operation=log"; + break; + case 'ln': + uri += "?operation=ln"; + break; default: setError(); return; } uri += "&operand1=" + encodeURIComponent(operand1); - uri += "&operand2=" + encodeURIComponent(operand2); + + // Only add operand2 for binary operations + var singleOperandOps = ['√', 'sin', 'cos', 'tan', 'log', 'ln']; + if (!singleOperandOps.includes(operation)) { + uri += "&operand2=" + encodeURIComponent(operand2); + } setLoading(true); @@ -116,6 +142,16 @@ function operationPressed(op) { state = states.operator; } +function scientificPressed(op) { + // Single operand operations execute immediately + var singleOperandOps = ['√', 'sin', 'cos', 'tan', 'log', 'ln']; + if (singleOperandOps.includes(op)) { + operand1 = getValue(); + calculate(operand1, null, op); + state = states.complete; + } +} + function equalPressed() { if (state < states.operand2) { state = states.complete; diff --git a/public/default.css b/public/default.css index bd14feb..f98104e 100644 --- a/public/default.css +++ b/public/default.css @@ -227,6 +227,20 @@ BODY { } /* Button type specific styling */ +.btn-scientific { + background: #6c757d; + color: white; + font-size: 1rem; +} + +.btn-scientific:hover { + background: #5a6268; +} + +.btn-scientific:active { + background: #545b62; +} + .btn[onclick*="operationPressed"] { background: var(--button-operator); color: white; diff --git a/public/index.html b/public/index.html index eaa7da7..f3422c1 100644 --- a/public/index.html +++ b/public/index.html @@ -1,14 +1,14 @@ - Modern Calculator + Scientific Palantír of Rivendell - +
-
+
0
@@ -16,10 +16,19 @@
- + + + + + + + + + + - + From cb4c9142269c29b6e165b2769eab8193e81e1982 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:46:00 +0000 Subject: [PATCH 4/5] Address code review feedback: fix operand passing, remove duplicates, restore CE button Co-authored-by: haslam93 <36418598+haslam93@users.noreply.github.com> --- api/controller.js | 7 ++++++- public/client.js | 9 +++++---- public/index.html | 5 +++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/api/controller.js b/api/controller.js index a3acfc1..5a1c3c1 100644 --- a/api/controller.js +++ b/api/controller.js @@ -52,5 +52,10 @@ exports.calculate = function(req, res) { } } - res.json({ result: operation(req.query.operand1, req.query.operand2) }); + // Call operation with appropriate number of operands + var result = singleOperandOps.includes(req.query.operation) + ? operation(req.query.operand1) + : operation(req.query.operand1, req.query.operand2); + + res.json({ result: result }); }; diff --git a/public/client.js b/public/client.js index 737ab62..a359c72 100644 --- a/public/client.js +++ b/public/client.js @@ -16,6 +16,9 @@ var operand1 = 0; var operand2 = 0; var operation = null; +// Single operand operations that execute immediately +var SINGLE_OPERAND_OPS = ['√', 'sin', 'cos', 'tan', 'log', 'ln']; + function calculate(operand1, operand2, operation) { var uri = location.origin + "/arithmetic"; @@ -62,8 +65,7 @@ function calculate(operand1, operand2, operation) { uri += "&operand1=" + encodeURIComponent(operand1); // Only add operand2 for binary operations - var singleOperandOps = ['√', 'sin', 'cos', 'tan', 'log', 'ln']; - if (!singleOperandOps.includes(operation)) { + if (!SINGLE_OPERAND_OPS.includes(operation)) { uri += "&operand2=" + encodeURIComponent(operand2); } @@ -144,8 +146,7 @@ function operationPressed(op) { function scientificPressed(op) { // Single operand operations execute immediately - var singleOperandOps = ['√', 'sin', 'cos', 'tan', 'log', 'ln']; - if (singleOperandOps.includes(op)) { + if (SINGLE_OPERAND_OPS.includes(op)) { operand1 = getValue(); calculate(operand1, null, op); state = states.complete; diff --git a/public/index.html b/public/index.html index f3422c1..e552658 100644 --- a/public/index.html +++ b/public/index.html @@ -26,9 +26,10 @@ - + - + + From 6b6a1688b1ed48ca1fb878681fdf269bc82ab113 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:36:10 +0000 Subject: [PATCH 5/5] Transform UI into verdant green theme of the Shire - as requested by haslam93 Co-authored-by: haslam93 <36418598+haslam93@users.noreply.github.com> --- public/default.css | 62 +++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/public/default.css b/public/default.css index f98104e..6baf245 100644 --- a/public/default.css +++ b/public/default.css @@ -1,44 +1,44 @@ -/* CSS Custom Properties for Modern Theming */ +/* CSS Custom Properties for The Green Theme of the Shire */ :root { - --primary-bg: #f0f2f5; - --calculator-bg: #ffffff; - --display-bg: #1e1e1e; - --display-text: #ffffff; - --button-bg: #f8f9fa; - --button-hover: #e9ecef; - --button-active: #dee2e6; - --button-operator: #007bff; - --button-operator-hover: #0056b3; - --button-operator-active: #004085; + --primary-bg: #d4f1d4; + --calculator-bg: #f0fff0; + --display-bg: #1a4d1a; + --display-text: #c8ffc8; + --button-bg: #e8f5e8; + --button-hover: #c8e6c8; + --button-active: #a8d6a8; + --button-operator: #2d8659; + --button-operator-hover: #257047; + --button-operator-active: #1d5a38; --button-equals: #28a745; --button-equals-hover: #1e7e34; --button-equals-active: #155724; --button-clear: #dc3545; --button-clear-hover: #c82333; --button-clear-active: #bd2130; - --text-primary: #212529; - --text-secondary: #6c757d; - --shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); - --shadow-md: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); - --shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175); + --text-primary: #1a4d1a; + --text-secondary: #4a7c4a; + --shadow-sm: 0 0.125rem 0.25rem rgba(0, 100, 0, 0.1); + --shadow-md: 0 0.5rem 1rem rgba(0, 100, 0, 0.2); + --shadow-lg: 0 1rem 3rem rgba(0, 100, 0, 0.25); --border-radius: 0.5rem; --border-radius-sm: 0.375rem; --transition-duration: 0.15s; --font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif; } -/* Dark mode support */ +/* Dark mode support - Green theme of Fangorn Forest */ @media (prefers-color-scheme: dark) { :root { - --primary-bg: #121212; - --calculator-bg: #1e1e1e; - --display-bg: #000000; - --display-text: #ffffff; - --button-bg: #2d2d2d; - --button-hover: #3d3d3d; - --button-active: #4d4d4d; - --text-primary: #ffffff; - --text-secondary: #adb5bd; + --primary-bg: #0a2f0a; + --calculator-bg: #1a3d1a; + --display-bg: #0d1f0d; + --display-text: #90ee90; + --button-bg: #2d4d2d; + --button-hover: #3d6d3d; + --button-active: #4d8d4d; + --text-primary: #90ee90; + --text-secondary: #6b9d6b; } } @@ -47,7 +47,7 @@ BODY { width: 100vw; padding: 0; margin: 0; - background: linear-gradient(135deg, var(--primary-bg) 0%, #e3e6ea 100%); + background: linear-gradient(135deg, var(--primary-bg) 0%, #b8e6b8 100%); font-family: var(--font-family); display: flex; justify-content: center; @@ -226,19 +226,19 @@ BODY { height: 200px; } -/* Button type specific styling */ +/* Button type specific styling - Scientific buttons like the leaves of Lothlórien */ .btn-scientific { - background: #6c757d; + background: #4a9d5f; color: white; font-size: 1rem; } .btn-scientific:hover { - background: #5a6268; + background: #3d8550; } .btn-scientific:active { - background: #545b62; + background: #2f6d40; } .btn[onclick*="operationPressed"] {