mani-calc 1.2.2 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,376 @@
1
+ /**
2
+ * Date/Time Calculator Module
3
+ * Handles date arithmetic, countdowns, and world clock
4
+ */
5
+
6
+ class DateTimeCalculator {
7
+ constructor() {
8
+ // Timezone offsets (from UTC)
9
+ this.timezones = {
10
+ // Americas
11
+ 'new york': -5, 'nyc': -5, 'est': -5, 'eastern': -5,
12
+ 'los angeles': -8, 'la': -8, 'pst': -8, 'pacific': -8,
13
+ 'chicago': -6, 'cst': -6, 'central': -6,
14
+ 'denver': -7, 'mst': -7, 'mountain': -7,
15
+ 'toronto': -5, 'vancouver': -8, 'mexico city': -6,
16
+ 'sao paulo': -3, 'brazil': -3, 'buenos aires': -3,
17
+
18
+ // Europe
19
+ 'london': 0, 'uk': 0, 'gmt': 0, 'utc': 0,
20
+ 'paris': 1, 'berlin': 1, 'rome': 1, 'madrid': 1, 'cet': 1,
21
+ 'amsterdam': 1, 'brussels': 1, 'vienna': 1, 'zurich': 1,
22
+ 'moscow': 3, 'istanbul': 3, 'athens': 2, 'helsinki': 2,
23
+
24
+ // Asia
25
+ 'india': 5.5, 'delhi': 5.5, 'mumbai': 5.5, 'ist': 5.5, 'kolkata': 5.5,
26
+ 'dubai': 4, 'uae': 4, 'abu dhabi': 4,
27
+ 'singapore': 8, 'hong kong': 8, 'hk': 8,
28
+ 'tokyo': 9, 'japan': 9, 'jst': 9,
29
+ 'seoul': 9, 'korea': 9, 'kst': 9,
30
+ 'beijing': 8, 'shanghai': 8, 'china': 8,
31
+ 'bangkok': 7, 'jakarta': 7, 'vietnam': 7, 'hanoi': 7,
32
+ 'taipei': 8, 'taiwan': 8,
33
+ 'manila': 8, 'philippines': 8,
34
+ 'kuala lumpur': 8, 'malaysia': 8,
35
+
36
+ // Oceania
37
+ 'sydney': 11, 'australia': 11, 'melbourne': 11, 'aest': 11,
38
+ 'perth': 8, 'brisbane': 10,
39
+ 'auckland': 13, 'new zealand': 13, 'nzst': 13,
40
+
41
+ // Africa/Middle East
42
+ 'cairo': 2, 'johannesburg': 2, 'lagos': 1,
43
+ 'riyadh': 3, 'saudi': 3, 'tel aviv': 2, 'israel': 2
44
+ };
45
+
46
+ // Common date patterns
47
+ this.months = {
48
+ 'jan': 0, 'january': 0,
49
+ 'feb': 1, 'february': 1,
50
+ 'mar': 2, 'march': 2,
51
+ 'apr': 3, 'april': 3,
52
+ 'may': 4,
53
+ 'jun': 5, 'june': 5,
54
+ 'jul': 6, 'july': 6,
55
+ 'aug': 7, 'august': 7,
56
+ 'sep': 8, 'sept': 8, 'september': 8,
57
+ 'oct': 9, 'october': 9,
58
+ 'nov': 10, 'november': 10,
59
+ 'dec': 11, 'december': 11
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Parse date query and return result
65
+ */
66
+ parse(query) {
67
+ const q = query.toLowerCase().trim();
68
+
69
+ // Time in location: "time in tokyo", "what time in london"
70
+ const timeMatch = q.match(/(?:what(?:'s| is)?\s+)?time\s+(?:in|at)\s+(.+)/i);
71
+ if (timeMatch) {
72
+ return this.getTimeInLocation(timeMatch[1].trim());
73
+ }
74
+
75
+ // Today +/- days: "today + 30 days", "today - 2 weeks"
76
+ const todayMatch = q.match(/today\s*([+-])\s*(\d+)\s*(day|days|week|weeks|month|months|year|years)/i);
77
+ if (todayMatch) {
78
+ return this.addToToday(todayMatch[1], parseInt(todayMatch[2]), todayMatch[3]);
79
+ }
80
+
81
+ // Days until/since: "days until dec 25", "days since jan 1"
82
+ const daysMatch = q.match(/(days?|weeks?|months?)\s+(until|since|from|to)\s+(.+)/i);
83
+ if (daysMatch) {
84
+ return this.calculateDuration(daysMatch[1], daysMatch[2], daysMatch[3]);
85
+ }
86
+
87
+ // What day: "what day is dec 25", "what day was jan 1 2020"
88
+ const whatDayMatch = q.match(/what\s+day\s+(?:is|was|will be)\s+(.+)/i);
89
+ if (whatDayMatch) {
90
+ return this.getWeekday(whatDayMatch[1]);
91
+ }
92
+
93
+ // Current date/time
94
+ if (q === 'today' || q === 'date' || q === 'now') {
95
+ return this.getCurrentDateTime();
96
+ }
97
+
98
+ if (q === 'time' || q === 'current time') {
99
+ return this.getCurrentTime();
100
+ }
101
+
102
+ // Week number
103
+ if (q === 'week' || q === 'week number' || q === 'what week') {
104
+ return this.getWeekNumber();
105
+ }
106
+
107
+ return null;
108
+ }
109
+
110
+ /**
111
+ * Get time in a specific location
112
+ */
113
+ getTimeInLocation(location) {
114
+ const loc = location.toLowerCase().trim();
115
+ const offset = this.timezones[loc];
116
+
117
+ if (offset === undefined) {
118
+ return {
119
+ error: `Unknown location: ${location}`,
120
+ type: 'error'
121
+ };
122
+ }
123
+
124
+ const now = new Date();
125
+ const utc = now.getTime() + (now.getTimezoneOffset() * 60000);
126
+ const targetTime = new Date(utc + (offset * 3600000));
127
+
128
+ const hours = targetTime.getHours();
129
+ const minutes = targetTime.getMinutes().toString().padStart(2, '0');
130
+ const ampm = hours >= 12 ? 'PM' : 'AM';
131
+ const hour12 = hours % 12 || 12;
132
+
133
+ const dayName = targetTime.toLocaleDateString('en-US', { weekday: 'short' });
134
+ const monthDay = targetTime.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
135
+
136
+ return {
137
+ result: `${hour12}:${minutes} ${ampm}`,
138
+ formatted: `${location.charAt(0).toUpperCase() + location.slice(1)}: ${hour12}:${minutes} ${ampm} (${dayName}, ${monthDay})`,
139
+ type: 'time',
140
+ location: location,
141
+ offset: offset
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Add/subtract from today
147
+ */
148
+ addToToday(operator, amount, unit) {
149
+ const today = new Date();
150
+ let multiplier = operator === '+' ? 1 : -1;
151
+
152
+ switch (unit.toLowerCase().replace(/s$/, '')) {
153
+ case 'day':
154
+ today.setDate(today.getDate() + (amount * multiplier));
155
+ break;
156
+ case 'week':
157
+ today.setDate(today.getDate() + (amount * 7 * multiplier));
158
+ break;
159
+ case 'month':
160
+ today.setMonth(today.getMonth() + (amount * multiplier));
161
+ break;
162
+ case 'year':
163
+ today.setFullYear(today.getFullYear() + (amount * multiplier));
164
+ break;
165
+ }
166
+
167
+ const dayName = today.toLocaleDateString('en-US', { weekday: 'long' });
168
+ const formatted = today.toLocaleDateString('en-US', {
169
+ weekday: 'long',
170
+ year: 'numeric',
171
+ month: 'long',
172
+ day: 'numeric'
173
+ });
174
+
175
+ return {
176
+ result: today.toISOString().split('T')[0],
177
+ formatted: formatted,
178
+ type: 'date',
179
+ dayName: dayName
180
+ };
181
+ }
182
+
183
+ /**
184
+ * Calculate days until/since a date
185
+ */
186
+ calculateDuration(unit, direction, dateStr) {
187
+ const targetDate = this.parseDate(dateStr);
188
+
189
+ if (!targetDate) {
190
+ return {
191
+ error: `Could not parse date: ${dateStr}`,
192
+ type: 'error'
193
+ };
194
+ }
195
+
196
+ const today = new Date();
197
+ today.setHours(0, 0, 0, 0);
198
+ targetDate.setHours(0, 0, 0, 0);
199
+
200
+ const diffTime = targetDate - today;
201
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
202
+
203
+ let result, formatted;
204
+ const unitLower = unit.toLowerCase().replace(/s$/, '');
205
+
206
+ if (unitLower === 'week') {
207
+ const weeks = Math.abs(Math.floor(diffDays / 7));
208
+ const remainingDays = Math.abs(diffDays % 7);
209
+ result = weeks;
210
+ formatted = `${weeks} week${weeks !== 1 ? 's' : ''}${remainingDays > 0 ? ` and ${remainingDays} day${remainingDays !== 1 ? 's' : ''}` : ''}`;
211
+ } else if (unitLower === 'month') {
212
+ const months = Math.abs(Math.floor(diffDays / 30));
213
+ result = months;
214
+ formatted = `${months} month${months !== 1 ? 's' : ''} (approximately)`;
215
+ } else {
216
+ result = Math.abs(diffDays);
217
+ formatted = `${Math.abs(diffDays)} day${Math.abs(diffDays) !== 1 ? 's' : ''}`;
218
+ }
219
+
220
+ const prefix = diffDays > 0 ? 'in' : 'ago';
221
+
222
+ return {
223
+ result: result,
224
+ formatted: diffDays === 0 ? 'Today!' : `${formatted} ${diffDays > 0 ? 'from now' : 'ago'}`,
225
+ type: 'duration',
226
+ days: diffDays
227
+ };
228
+ }
229
+
230
+ /**
231
+ * Get weekday for a date
232
+ */
233
+ getWeekday(dateStr) {
234
+ const date = this.parseDate(dateStr);
235
+
236
+ if (!date) {
237
+ return {
238
+ error: `Could not parse date: ${dateStr}`,
239
+ type: 'error'
240
+ };
241
+ }
242
+
243
+ const dayName = date.toLocaleDateString('en-US', { weekday: 'long' });
244
+ const formatted = date.toLocaleDateString('en-US', {
245
+ weekday: 'long',
246
+ year: 'numeric',
247
+ month: 'long',
248
+ day: 'numeric'
249
+ });
250
+
251
+ return {
252
+ result: dayName,
253
+ formatted: formatted,
254
+ type: 'date'
255
+ };
256
+ }
257
+
258
+ /**
259
+ * Parse various date formats
260
+ */
261
+ parseDate(dateStr) {
262
+ const str = dateStr.toLowerCase().trim();
263
+
264
+ // Named dates
265
+ if (str === 'christmas' || str === 'xmas') {
266
+ const year = new Date().getMonth() >= 11 && new Date().getDate() > 25
267
+ ? new Date().getFullYear() + 1
268
+ : new Date().getFullYear();
269
+ return new Date(year, 11, 25);
270
+ }
271
+ if (str === 'new year' || str === 'new years' || str === "new year's") {
272
+ return new Date(new Date().getFullYear() + 1, 0, 1);
273
+ }
274
+ if (str === 'halloween') {
275
+ const year = new Date().getMonth() > 9 ? new Date().getFullYear() + 1 : new Date().getFullYear();
276
+ return new Date(year, 9, 31);
277
+ }
278
+ if (str === 'valentine' || str === "valentine's" || str === 'valentines') {
279
+ const year = new Date().getMonth() > 1 ? new Date().getFullYear() + 1 : new Date().getFullYear();
280
+ return new Date(year, 1, 14);
281
+ }
282
+
283
+ // Month day format: "dec 25", "december 25", "25 dec"
284
+ const monthDayMatch = str.match(/(\d{1,2})\s+([a-z]+)|([a-z]+)\s+(\d{1,2})(?:\s+(\d{4}))?/);
285
+ if (monthDayMatch) {
286
+ let day, monthStr, year;
287
+ if (monthDayMatch[1]) {
288
+ day = parseInt(monthDayMatch[1]);
289
+ monthStr = monthDayMatch[2];
290
+ } else {
291
+ monthStr = monthDayMatch[3];
292
+ day = parseInt(monthDayMatch[4]);
293
+ year = monthDayMatch[5] ? parseInt(monthDayMatch[5]) : null;
294
+ }
295
+
296
+ const month = this.months[monthStr];
297
+ if (month !== undefined && day >= 1 && day <= 31) {
298
+ const targetYear = year || new Date().getFullYear();
299
+ return new Date(targetYear, month, day);
300
+ }
301
+ }
302
+
303
+ // Standard date formats
304
+ const date = new Date(dateStr);
305
+ if (!isNaN(date.getTime())) {
306
+ return date;
307
+ }
308
+
309
+ return null;
310
+ }
311
+
312
+ /**
313
+ * Get current date and time
314
+ */
315
+ getCurrentDateTime() {
316
+ const now = new Date();
317
+ return {
318
+ result: now.toLocaleDateString('en-US', {
319
+ weekday: 'long',
320
+ year: 'numeric',
321
+ month: 'long',
322
+ day: 'numeric'
323
+ }),
324
+ formatted: now.toLocaleString('en-US', {
325
+ weekday: 'long',
326
+ year: 'numeric',
327
+ month: 'long',
328
+ day: 'numeric',
329
+ hour: 'numeric',
330
+ minute: '2-digit',
331
+ hour12: true
332
+ }),
333
+ type: 'datetime'
334
+ };
335
+ }
336
+
337
+ /**
338
+ * Get current time
339
+ */
340
+ getCurrentTime() {
341
+ const now = new Date();
342
+ return {
343
+ result: now.toLocaleTimeString('en-US', {
344
+ hour: 'numeric',
345
+ minute: '2-digit',
346
+ hour12: true
347
+ }),
348
+ formatted: now.toLocaleTimeString('en-US', {
349
+ hour: 'numeric',
350
+ minute: '2-digit',
351
+ second: '2-digit',
352
+ hour12: true
353
+ }),
354
+ type: 'time'
355
+ };
356
+ }
357
+
358
+ /**
359
+ * Get current week number
360
+ */
361
+ getWeekNumber() {
362
+ const now = new Date();
363
+ const start = new Date(now.getFullYear(), 0, 1);
364
+ const diff = now - start;
365
+ const oneWeek = 604800000;
366
+ const weekNum = Math.ceil((diff + start.getDay() * 86400000) / oneWeek);
367
+
368
+ return {
369
+ result: weekNum,
370
+ formatted: `Week ${weekNum} of ${now.getFullYear()}`,
371
+ type: 'week'
372
+ };
373
+ }
374
+ }
375
+
376
+ module.exports = DateTimeCalculator;
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Programmer Calculator Module
3
+ * Handles hex, binary, octal conversions and bitwise operations
4
+ */
5
+
6
+ class ProgrammerCalculator {
7
+ constructor() {
8
+ // Regex patterns for different number formats
9
+ this.patterns = {
10
+ hex: /^(?:0x|#)?([0-9a-fA-F]+)$/,
11
+ binary: /^(?:0b)?([01]+)$/,
12
+ octal: /^(?:0o)?([0-7]+)$/,
13
+ decimal: /^(\d+)$/
14
+ };
15
+ }
16
+
17
+ /**
18
+ * Parse programmer calculation query
19
+ */
20
+ parse(query) {
21
+ const q = query.toLowerCase().trim();
22
+
23
+ // Convert to decimal: "0xFF to decimal", "hex FF to dec"
24
+ const toDecMatch = q.match(/(?:0x|hex\s*)?([0-9a-f]+)\s+to\s+(?:dec|decimal)/i);
25
+ if (toDecMatch) {
26
+ return this.hexToDecimal(toDecMatch[1]);
27
+ }
28
+
29
+ // Convert to hex: "255 to hex", "decimal 255 to hex"
30
+ const toHexMatch = q.match(/(?:decimal\s+)?(\d+)\s+to\s+hex/i);
31
+ if (toHexMatch) {
32
+ return this.decimalToHex(parseInt(toHexMatch[1]));
33
+ }
34
+
35
+ // Convert to binary: "255 to binary", "255 to bin"
36
+ const toBinMatch = q.match(/(?:decimal\s+)?(\d+)\s+to\s+(?:bin|binary)/i);
37
+ if (toBinMatch) {
38
+ return this.decimalToBinary(parseInt(toBinMatch[1]));
39
+ }
40
+
41
+ // Convert binary to decimal: "0b1111 to decimal", "binary 1111 to dec"
42
+ const binToDecMatch = q.match(/(?:0b|binary\s+)?([01]+)\s+to\s+(?:dec|decimal)/i);
43
+ if (binToDecMatch && q.includes('bin') || q.startsWith('0b')) {
44
+ return this.binaryToDecimal(binToDecMatch[1]);
45
+ }
46
+
47
+ // Convert to octal: "255 to octal", "255 to oct"
48
+ const toOctMatch = q.match(/(?:decimal\s+)?(\d+)\s+to\s+(?:oct|octal)/i);
49
+ if (toOctMatch) {
50
+ return this.decimalToOctal(parseInt(toOctMatch[1]));
51
+ }
52
+
53
+ // Quick hex prefix: "hex 255", "hex(255)"
54
+ const hexMatch = q.match(/^hex\s*\(?(\d+)\)?$/i);
55
+ if (hexMatch) {
56
+ return this.decimalToHex(parseInt(hexMatch[1]));
57
+ }
58
+
59
+ // Quick binary prefix: "bin 255", "binary 255"
60
+ const binMatch = q.match(/^(?:bin|binary)\s*\(?(\d+)\)?$/i);
61
+ if (binMatch) {
62
+ return this.decimalToBinary(parseInt(binMatch[1]));
63
+ }
64
+
65
+ // Quick octal prefix: "oct 255", "octal 255"
66
+ const octMatch = q.match(/^(?:oct|octal)\s*\(?(\d+)\)?$/i);
67
+ if (octMatch) {
68
+ return this.decimalToOctal(parseInt(octMatch[1]));
69
+ }
70
+
71
+ // Bitwise operations: "255 AND 128", "255 OR 64", "NOT 255", "255 XOR 128"
72
+ const bitwiseMatch = q.match(/(\d+)\s+(and|or|xor|nand|nor)\s+(\d+)/i);
73
+ if (bitwiseMatch) {
74
+ return this.bitwiseOperation(
75
+ parseInt(bitwiseMatch[1]),
76
+ bitwiseMatch[2].toLowerCase(),
77
+ parseInt(bitwiseMatch[3])
78
+ );
79
+ }
80
+
81
+ // NOT operation: "NOT 255", "~255"
82
+ const notMatch = q.match(/(?:not|~)\s*(\d+)/i);
83
+ if (notMatch) {
84
+ return this.bitwiseNot(parseInt(notMatch[1]));
85
+ }
86
+
87
+ // Shift operations: "255 << 2", "255 >> 2"
88
+ const shiftMatch = q.match(/(\d+)\s*(<<|>>|>>>)\s*(\d+)/);
89
+ if (shiftMatch) {
90
+ return this.bitShift(
91
+ parseInt(shiftMatch[1]),
92
+ shiftMatch[2],
93
+ parseInt(shiftMatch[3])
94
+ );
95
+ }
96
+
97
+ // Direct 0x prefix detection
98
+ if (q.startsWith('0x')) {
99
+ return this.hexToDecimal(q.slice(2));
100
+ }
101
+
102
+ // Direct 0b prefix detection
103
+ if (q.startsWith('0b')) {
104
+ return this.binaryToDecimal(q.slice(2));
105
+ }
106
+
107
+ return null;
108
+ }
109
+
110
+ /**
111
+ * Hex to Decimal
112
+ */
113
+ hexToDecimal(hex) {
114
+ const decimal = parseInt(hex, 16);
115
+ if (isNaN(decimal)) {
116
+ return { error: `Invalid hex: ${hex}`, type: 'error' };
117
+ }
118
+ return {
119
+ result: decimal,
120
+ formatted: `0x${hex.toUpperCase()} = ${decimal} (decimal)`,
121
+ type: 'programmer',
122
+ conversions: this.getAllConversions(decimal)
123
+ };
124
+ }
125
+
126
+ /**
127
+ * Decimal to Hex
128
+ */
129
+ decimalToHex(decimal) {
130
+ if (isNaN(decimal)) {
131
+ return { error: `Invalid number: ${decimal}`, type: 'error' };
132
+ }
133
+ const hex = decimal.toString(16).toUpperCase();
134
+ return {
135
+ result: `0x${hex}`,
136
+ formatted: `${decimal} = 0x${hex} (hex)`,
137
+ type: 'programmer',
138
+ conversions: this.getAllConversions(decimal)
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Decimal to Binary
144
+ */
145
+ decimalToBinary(decimal) {
146
+ if (isNaN(decimal)) {
147
+ return { error: `Invalid number: ${decimal}`, type: 'error' };
148
+ }
149
+ const binary = decimal.toString(2);
150
+ // Pad to 8-bit boundaries
151
+ const padded = binary.padStart(Math.ceil(binary.length / 8) * 8, '0');
152
+ const formatted = padded.replace(/(.{4})/g, '$1 ').trim();
153
+ return {
154
+ result: `0b${binary}`,
155
+ formatted: `${decimal} = ${formatted} (binary)`,
156
+ type: 'programmer',
157
+ conversions: this.getAllConversions(decimal)
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Binary to Decimal
163
+ */
164
+ binaryToDecimal(binary) {
165
+ const clean = binary.replace(/\s/g, '');
166
+ const decimal = parseInt(clean, 2);
167
+ if (isNaN(decimal)) {
168
+ return { error: `Invalid binary: ${binary}`, type: 'error' };
169
+ }
170
+ return {
171
+ result: decimal,
172
+ formatted: `0b${clean} = ${decimal} (decimal)`,
173
+ type: 'programmer',
174
+ conversions: this.getAllConversions(decimal)
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Decimal to Octal
180
+ */
181
+ decimalToOctal(decimal) {
182
+ if (isNaN(decimal)) {
183
+ return { error: `Invalid number: ${decimal}`, type: 'error' };
184
+ }
185
+ const octal = decimal.toString(8);
186
+ return {
187
+ result: `0o${octal}`,
188
+ formatted: `${decimal} = 0o${octal} (octal)`,
189
+ type: 'programmer',
190
+ conversions: this.getAllConversions(decimal)
191
+ };
192
+ }
193
+
194
+ /**
195
+ * Bitwise operations
196
+ */
197
+ bitwiseOperation(a, op, b) {
198
+ let result;
199
+ switch (op) {
200
+ case 'and': result = a & b; break;
201
+ case 'or': result = a | b; break;
202
+ case 'xor': result = a ^ b; break;
203
+ case 'nand': result = ~(a & b); break;
204
+ case 'nor': result = ~(a | b); break;
205
+ default: return { error: `Unknown operation: ${op}`, type: 'error' };
206
+ }
207
+ return {
208
+ result: result,
209
+ formatted: `${a} ${op.toUpperCase()} ${b} = ${result}`,
210
+ type: 'programmer',
211
+ conversions: this.getAllConversions(result)
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Bitwise NOT
217
+ */
218
+ bitwiseNot(a) {
219
+ // For 32-bit unsigned representation
220
+ const result = ~a >>> 0;
221
+ return {
222
+ result: result,
223
+ formatted: `NOT ${a} = ${result} (32-bit unsigned)`,
224
+ type: 'programmer',
225
+ conversions: this.getAllConversions(result)
226
+ };
227
+ }
228
+
229
+ /**
230
+ * Bit shift operations
231
+ */
232
+ bitShift(a, op, b) {
233
+ let result;
234
+ switch (op) {
235
+ case '<<': result = a << b; break;
236
+ case '>>': result = a >> b; break;
237
+ case '>>>': result = a >>> b; break;
238
+ default: return { error: `Unknown shift: ${op}`, type: 'error' };
239
+ }
240
+ return {
241
+ result: result,
242
+ formatted: `${a} ${op} ${b} = ${result}`,
243
+ type: 'programmer',
244
+ conversions: this.getAllConversions(result)
245
+ };
246
+ }
247
+
248
+ /**
249
+ * Get all conversions for a number
250
+ */
251
+ getAllConversions(decimal) {
252
+ if (decimal < 0) {
253
+ // Handle negative numbers with 32-bit representation
254
+ decimal = decimal >>> 0;
255
+ }
256
+ return {
257
+ decimal: decimal,
258
+ hex: '0x' + decimal.toString(16).toUpperCase(),
259
+ binary: '0b' + decimal.toString(2),
260
+ octal: '0o' + decimal.toString(8)
261
+ };
262
+ }
263
+ }
264
+
265
+ module.exports = ProgrammerCalculator;