{"format":1,"manifest":{"name":"calc-convert","publisher":"vyloxi","version":"1.0.0","displayName":"Calc and Convert","description":"A calculator for the current line, unit conversion, currency conversion with fixed rates, and a number base converter.","engines":{"ferrum":"^0.1.0"},"categories":["Tools"],"icon":"icon.png","repository":"https://github.com/voukengdongmofrankysteve/ferrum-market","license":"MIT","main":"extension.js","activationEvents":["onCommand:calcConvert.calculate","onCommand:calcConvert.calculateReplace","onCommand:calcConvert.calculateAsk","onCommand:calcConvert.units","onCommand:calcConvert.currency","onCommand:calcConvert.listCurrencies","onCommand:calcConvert.bases","onCommand:calcConvert.baseFrom"],"permissions":[],"contributes":{"commands":[{"command":"calcConvert.calculate","title":"Calculate Line or Selection","category":"Calc and Convert"},{"command":"calcConvert.calculateReplace","title":"Calculate and Replace with the Result","category":"Calc and Convert"},{"command":"calcConvert.calculateAsk","title":"Calculator...","category":"Calc and Convert"},{"command":"calcConvert.units","title":"Convert Units...","category":"Calc and Convert"},{"command":"calcConvert.currency","title":"Convert Currency...","category":"Calc and Convert"},{"command":"calcConvert.listCurrencies","title":"List Currencies","category":"Calc and Convert"},{"command":"calcConvert.bases","title":"Convert Number Under Cursor to Another Base...","category":"Calc and Convert"},{"command":"calcConvert.baseFrom","title":"Show a Number in All Bases...","category":"Calc and Convert"}],"keybindings":[{"command":"calcConvert.calculate","key":"Ctrl+Alt+="}],"configuration":{"title":"Calc and Convert","properties":{"calcConvert.precision":{"type":"number","default":10,"description":"How many significant digits to show in results."},"calcConvert.defaultCurrency":{"type":"string","default":"USD","description":"The currency to convert to when you only type an amount and a currency, like \"50 eur\"."},"calcConvert.customRates":{"type":"string","default":"","description":"Your own rates per 1 USD, for example \"EUR=0.93, GBP=0.8, XAF=610\". They replace the built in ones."}}}}},"files":{"icon.png":{"encoding":"base64","content":"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"},"extension.js":{"encoding":"utf8","content":"// Calc and Convert: a calculator for the line you are on, unit conversion, currency conversion with fixed rates\n// you can edit, and a number base converter. No network, no permissions.\n\n// ---- calculator: a small recursive descent parser, no eval ---------------------------------------------------------\nconst FUNCS = {\n  sqrt: Math.sqrt, cbrt: Math.cbrt, abs: Math.abs, sin: Math.sin, cos: Math.cos, tan: Math.tan, asin: Math.asin, acos: Math.acos, atan: Math.atan,\n  ln: Math.log, log: Math.log10, log2: Math.log2, exp: Math.exp, round: Math.round, floor: Math.floor, ceil: Math.ceil, trunc: Math.trunc, sign: Math.sign,\n  min: Math.min, max: Math.max, pow: Math.pow, hypot: Math.hypot, atan2: Math.atan2, deg: (x) => (x * 180) / Math.PI, rad: (x) => (x * Math.PI) / 180,\n  fact: (n) => { if (!Number.isInteger(n) || n < 0 || n > 170) throw new Error('fact needs an integer from 0 to 170'); let r = 1; for (let i = 2; i <= n; i++) r *= i; return r; },\n  avg: (...a) => a.reduce((x, y) => x + y, 0) / a.length, sum: (...a) => a.reduce((x, y) => x + y, 0),\n};\nconst CONSTS = { pi: Math.PI, e: Math.E, tau: Math.PI * 2, phi: (1 + Math.sqrt(5)) / 2 };\n\nfunction tokenize(src) {\n  const out = [];\n  const re = /\\s*(?:(0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|\\d[\\d_]*\\.?\\d*(?:[eE][+-]?\\d+)?|\\.\\d+(?:[eE][+-]?\\d+)?)|([A-Za-z_][A-Za-z0-9_]*)|(\\*\\*|[-+*/%^(),!])|(\\S))/y;\n  let m;\n  re.lastIndex = 0;\n  while (re.lastIndex < src.length && (m = re.exec(src))) {\n    if (m[1] !== undefined) out.push({ t: 'num', v: Number(m[1].replace(/_/g, '')) });\n    else if (m[2] !== undefined) out.push({ t: 'id', v: m[2] });\n    else if (m[3] !== undefined) out.push({ t: 'op', v: m[3] });\n    else throw new Error('Unexpected \"' + m[4] + '\"');\n  }\n  return out;\n}\n\n/** Evaluates an arithmetic expression. Supports + - * / % (modulo or percent) ^ ** ! ( ) functions, constants and `ans`. */\nfunction evaluate(src, vars = {}) {\n  const toks = tokenize(src);\n  if (!toks.length) throw new Error('Nothing to calculate');\n  let i = 0;\n  const peek = () => toks[i];\n  const take = () => toks[i++];\n  const isOp = (v) => peek() && peek().t === 'op' && peek().v === v;\n\n  function expr() {\n    let v = term();\n    while (isOp('+') || isOp('-')) {\n      const op = take().v;\n      const r = term();\n      v = op === '+' ? v + r : v - r;\n    }\n    return v;\n  }\n  function term() {\n    let v = unary();\n    while (isOp('*') || isOp('/') || isOp('%')) {\n      const op = take().v;\n      // \"50%\" followed by nothing useful is a percent; \"7 % 3\" is a modulo.\n      if (op === '%' && !startsOperand()) { v = v / 100; continue; }\n      const r = unary();\n      v = op === '*' ? v * r : op === '/' ? v / r : v % r;\n    }\n    return v;\n  }\n  function startsOperand() {\n    const t = peek();\n    return !!t && (t.t === 'num' || t.t === 'id' || (t.t === 'op' && (t.v === '(' || t.v === '-' || t.v === '+')));\n  }\n  function unary() {\n    if (isOp('-')) { take(); return -unary(); }\n    if (isOp('+')) { take(); return unary(); }\n    return power();\n  }\n  function power() {\n    let b = postfix();\n    if (isOp('^') || isOp('**')) { take(); return Math.pow(b, unary()); }\n    return b;\n  }\n  function postfix() {\n    let v = atom();\n    while (isOp('!')) { take(); v = FUNCS.fact(v); }\n    if (isOp('%') && !(toks[i + 1] && startsOperandAt(i + 1))) { take(); v = v / 100; }\n    return v;\n  }\n  function startsOperandAt(k) {\n    const t = toks[k];\n    return !!t && (t.t === 'num' || t.t === 'id' || (t.t === 'op' && t.v === '('));\n  }\n  function atom() {\n    const t = take();\n    if (!t) throw new Error('The expression ends too early');\n    if (t.t === 'num') return t.v;\n    if (t.t === 'op' && t.v === '(') {\n      const v = expr();\n      if (!isOp(')')) throw new Error('Missing )');\n      take();\n      return v;\n    }\n    if (t.t === 'id') {\n      const name = t.v.toLowerCase();\n      if (isOp('(')) {\n        take();\n        const args = [];\n        if (!isOp(')')) {\n          args.push(expr());\n          while (isOp(',')) { take(); args.push(expr()); }\n        }\n        if (!isOp(')')) throw new Error('Missing )');\n        take();\n        if (!FUNCS[name]) throw new Error('Unknown function ' + t.v);\n        return FUNCS[name](...args);\n      }\n      if (name in vars) return vars[name];\n      if (name in CONSTS) return CONSTS[name];\n      throw new Error('Unknown name ' + t.v);\n    }\n    throw new Error('Unexpected \"' + t.v + '\"');\n  }\n\n  const v = expr();\n  if (i < toks.length) throw new Error('Unexpected \"' + toks[i].v + '\"');\n  if (typeof v !== 'number' || Number.isNaN(v)) throw new Error('That is not a number');\n  return v;\n}\n\nfunction fmt(n, digits = 10) {\n  if (!Number.isFinite(n)) return String(n);\n  const r = Number(n.toPrecision(digits));\n  if (Math.abs(r) >= 1e21 || (Math.abs(r) < 1e-7 && r !== 0)) return r.toExponential();\n  return String(r);\n}\n\n// ---- units -----------------------------------------------------------------------------------------------------------\n// Every table maps a unit to its size in the base unit of the group.\nconst GROUPS = {\n  length: { base: 'm', units: { m: 1, meter: 1, meters: 1, metre: 1, metres: 1, km: 1000, kilometer: 1000, kilometers: 1000, cm: 0.01, mm: 0.001, um: 1e-6, nm: 1e-9, mi: 1609.344, mile: 1609.344, miles: 1609.344, yd: 0.9144, yard: 0.9144, yards: 0.9144, ft: 0.3048, foot: 0.3048, feet: 0.3048, in: 0.0254, inch: 0.0254, inches: 0.0254, nmi: 1852 } },\n  mass: { base: 'kg', units: { kg: 1, kilogram: 1, kilograms: 1, g: 0.001, gram: 0.001, grams: 0.001, mg: 1e-6, t: 1000, tonne: 1000, tonnes: 1000, lb: 0.45359237, lbs: 0.45359237, pound: 0.45359237, pounds: 0.45359237, oz: 0.028349523125, ounce: 0.028349523125, ounces: 0.028349523125, st: 6.35029318, stone: 6.35029318 } },\n  volume: { base: 'l', units: { l: 1, liter: 1, liters: 1, litre: 1, litres: 1, ml: 0.001, cl: 0.01, dl: 0.1, m3: 1000, gal: 3.785411784, gallon: 3.785411784, gallons: 3.785411784, qt: 0.946352946, pt: 0.473176473, cup: 0.2365882365, cups: 0.2365882365, floz: 0.0295735295625, tbsp: 0.01478676478125, tsp: 0.00492892159375 } },\n  area: { base: 'm2', units: { m2: 1, km2: 1e6, cm2: 1e-4, mm2: 1e-6, ha: 10000, hectare: 10000, hectares: 10000, acre: 4046.8564224, acres: 4046.8564224, ft2: 0.09290304, sqft: 0.09290304, in2: 0.00064516, yd2: 0.83612736, mi2: 2589988.110336 } },\n  time: { base: 's', units: { s: 1, sec: 1, second: 1, seconds: 1, ms: 0.001, us: 1e-6, ns: 1e-9, min: 60, minute: 60, minutes: 60, h: 3600, hr: 3600, hour: 3600, hours: 3600, d: 86400, day: 86400, days: 86400, wk: 604800, week: 604800, weeks: 604800, month: 2629746, months: 2629746, yr: 31556952, year: 31556952, years: 31556952 } },\n  data: { base: 'b', units: { b: 1, byte: 1, bytes: 1, kb: 1000, mb: 1e6, gb: 1e9, tb: 1e12, pb: 1e15, kib: 1024, mib: 1048576, gib: 1073741824, tib: 1099511627776, pib: 1125899906842624, bit: 0.125, bits: 0.125, kbit: 125, mbit: 125000, gbit: 125000000 } },\n  speed: { base: 'm/s', units: { 'm/s': 1, 'km/h': 1 / 3.6, kmh: 1 / 3.6, kph: 1 / 3.6, mph: 0.44704, 'mi/h': 0.44704, kn: 0.514444, knot: 0.514444, knots: 0.514444, 'ft/s': 0.3048 } },\n  pressure: { base: 'pa', units: { pa: 1, kpa: 1000, mpa: 1e6, bar: 1e5, mbar: 100, atm: 101325, psi: 6894.757293168, mmhg: 133.322387415, torr: 133.322387415 } },\n  energy: { base: 'j', units: { j: 1, kj: 1000, mj: 1e6, cal: 4.184, kcal: 4184, wh: 3600, kwh: 3.6e6, btu: 1055.05585262, ev: 1.602176634e-19 } },\n  angle: { base: 'rad', units: { rad: 1, deg: Math.PI / 180, degree: Math.PI / 180, degrees: Math.PI / 180, grad: Math.PI / 200, turn: Math.PI * 2 } },\n};\nconst TEMPS = new Set(['c', 'f', 'k', 'celsius', 'fahrenheit', 'kelvin']);\n\nfunction unitGroup(u) {\n  const k = u.toLowerCase();\n  if (TEMPS.has(k)) return 'temperature';\n  for (const [g, def] of Object.entries(GROUPS)) if (k in def.units) return g;\n  return null;\n}\nconst tempKey = (u) => ({ c: 'c', celsius: 'c', f: 'f', fahrenheit: 'f', k: 'k', kelvin: 'k' })[u.toLowerCase()];\n\nfunction convertUnit(value, from, to) {\n  const gf = unitGroup(from);\n  const gt = unitGroup(to);\n  if (!gf) throw new Error('Unknown unit \"' + from + '\"');\n  if (!gt) throw new Error('Unknown unit \"' + to + '\"');\n  if (gf !== gt) throw new Error('Cannot convert ' + gf + ' (' + from + ') to ' + gt + ' (' + to + ')');\n  if (gf === 'temperature') {\n    const a = tempKey(from);\n    const b = tempKey(to);\n    const c = a === 'c' ? value : a === 'f' ? ((value - 32) * 5) / 9 : value - 273.15;\n    return b === 'c' ? c : b === 'f' ? (c * 9) / 5 + 32 : c + 273.15;\n  }\n  const t = GROUPS[gf].units;\n  return (value * t[from.toLowerCase()]) / t[to.toLowerCase()];\n}\n\n/** Parses \"12.5 km to mi\", \"70 f in c\", \"3 hours as minutes\". */\nfunction parseQuantity(text) {\n  const m = /^\\s*([-+]?[\\d.,_]+(?:e[-+]?\\d+)?)\\s*([A-Za-z][A-Za-z0-9/]*)\\s+(?:to|in|as|into|->|=>)\\s+([A-Za-z][A-Za-z0-9/]*)\\s*$/i.exec(text);\n  if (!m) return null;\n  const value = Number(m[1].replace(/[,_]/g, ''));\n  if (Number.isNaN(value)) return null;\n  return { value, from: m[2], to: m[3] };\n}\n\n// ---- currencies: fixed rates, units per 1 USD -------------------------------------------------------------------------\n// These are approximate and fixed on purpose: no network is used. Edit them in the settings (\"EUR=0.93, GBP=0.8\").\nconst RATES = { USD: 1, EUR: 0.92, GBP: 0.79, JPY: 150, CAD: 1.37, AUD: 1.52, NZD: 1.65, CHF: 0.88, CNY: 7.2, HKD: 7.8, INR: 83.2, SGD: 1.34, KRW: 1340, SEK: 10.6, NOK: 10.7, DKK: 6.9, PLN: 4.0, CZK: 23, TRY: 32, RUB: 92, BRL: 5.0, MXN: 17.5, ARS: 900, CLP: 940, COP: 3900, ZAR: 18.4, NGN: 1500, GHS: 12.5, KES: 129, EGP: 48, MAD: 10, XAF: 603, XOF: 603, RWF: 1300, UGX: 3800, TZS: 2600, AED: 3.67, SAR: 3.75, ILS: 3.7, THB: 36, IDR: 15700, MYR: 4.7, PHP: 56, VND: 24500, PKR: 278, BDT: 110, UAH: 40 };\n\nfunction parseRates(text) {\n  const out = {};\n  for (const part of String(text || '').split(/[,;\\s]+/).filter(Boolean)) {\n    const m = /^([A-Za-z]{3})=([0-9.]+)$/.exec(part);\n    if (m && Number(m[2]) > 0) out[m[1].toUpperCase()] = Number(m[2]);\n  }\n  return out;\n}\n\nfunction convertCurrency(value, from, to, custom = {}) {\n  const table = { ...RATES, ...custom };\n  const a = table[from.toUpperCase()];\n  const b = table[to.toUpperCase()];\n  if (!a) throw new Error('No rate for ' + from.toUpperCase());\n  if (!b) throw new Error('No rate for ' + to.toUpperCase());\n  return (value / a) * b;\n}\n\n// ---- number bases ----------------------------------------------------------------------------------------------------\nfunction parseInteger(text, base) {\n  let s = String(text).trim().replace(/[_\\s]/g, '').toLowerCase();\n  let neg = false;\n  if (s.startsWith('-')) { neg = true; s = s.slice(1); }\n  const prefixes = { '0x': 16, '0b': 2, '0o': 8 };\n  const p = s.slice(0, 2);\n  if (prefixes[p]) { if (base && base !== prefixes[p]) throw new Error(text + ' does not look like base ' + base); base = prefixes[p]; s = s.slice(2); }\n  base = base || 10;\n  const digits = '0123456789abcdefghijklmnopqrstuvwxyz'.slice(0, base);\n  if (!s || [...s].some((c) => !digits.includes(c))) throw new Error('\"' + text + '\" is not a base ' + base + ' number');\n  let v = 0n;\n  for (const c of s) v = v * BigInt(base) + BigInt(digits.indexOf(c));\n  return neg ? -v : v;\n}\nconst toBase = (v, base) => v.toString(base);\nfunction allBases(v) {\n  return [['Binary (2)', (v < 0n ? '-0b' : '0b') + (v < 0n ? -v : v).toString(2)], ['Octal (8)', (v < 0n ? '-0o' : '0o') + (v < 0n ? -v : v).toString(8)], ['Decimal (10)', v.toString(10)], ['Hexadecimal (16)', (v < 0n ? '-0x' : '0x') + (v < 0n ? -v : v).toString(16).toUpperCase()]];\n}\n\nexports._test = { evaluate, fmt, convertUnit, parseQuantity, unitGroup, convertCurrency, parseRates, parseInteger, toBase, allBases, RATES };\n\nexports.activate = function (context) {\n  let ans = 0;\n  const reg = (id, fn) => context.subscriptions.push(ferrum.commands.register(id, fn));\n  const customRates = () => parseRates(ferrum.settings.get('calcConvert.customRates'));\n  const digits = () => Math.min(15, Math.max(2, Number(ferrum.settings.get('calcConvert.precision')) || 10));\n\n  /** The text to work on: the selection, or the current line. */\n  async function subject() {\n    const doc = await ferrum.editor.active();\n    if (!doc) { ferrum.window.showMessage('Open a file first.', 'warn'); return null; }\n    if (doc.selectedText) return { doc, text: doc.selectedText, range: doc.selection, whole: false };\n    const line = doc.selection.start.line;\n    const text = await ferrum.editor.getLine(line);\n    return { doc, text, range: { start: { line, col: 0 }, end: { line, col: text.length } }, whole: true };\n  }\n\n  /** Strips a result already written after \"=\" so running it twice does not stack results. */\n  const expression = (t) => t.replace(/=\\s*[^=]*$/, '').replace(/^\\s*[-*]\\s+/, '').trim();\n\n  async function calc(mode) {\n    const s = await subject();\n    if (!s) return;\n    const src = expression(s.text);\n    try {\n      const v = evaluate(src, { ans });\n      ans = v;\n      const out = fmt(v, digits());\n      if (mode === 'replace') await ferrum.editor.replace(s.range, out);\n      else if (s.whole) await ferrum.editor.replace({ start: s.range.end, end: s.range.end }, ' = ' + out), ferrum.window.showMessage(src + ' = ' + out);\n      else await ferrum.editor.replace(s.range, s.text.replace(/=\\s*[^=]*$/, '').trimEnd() + ' = ' + out);\n    } catch (e) {\n      ferrum.window.showMessage('Cannot calculate \"' + src + '\": ' + e.message, 'warn');\n    }\n  }\n\n  async function deliver(label, text) {\n    const pick = await ferrum.window.showQuickPick(\n      [{ label: 'Insert ' + text, detail: label, what: 'insert' }, { label: 'Show only', detail: label, what: 'show' }],\n      { placeholder: label },\n    );\n    if (!pick) return;\n    if (pick.what === 'insert') await ferrum.editor.insert(text);\n    else ferrum.window.showMessage(label);\n  }\n\n  reg('calcConvert.calculate', () => calc('append'));\n  reg('calcConvert.calculateReplace', () => calc('replace'));\n  reg('calcConvert.calculateAsk', async () => {\n    const src = await ferrum.window.showInputBox({ prompt: 'Calculate', placeholder: '(12 + 8) * 3 / 4, sqrt(2), 15% * 80' });\n    if (!src) return;\n    try {\n      const v = evaluate(src, { ans });\n      ans = v;\n      await deliver(src + ' = ' + fmt(v, digits()), fmt(v, digits()));\n    } catch (e) {\n      ferrum.window.showMessage('Cannot calculate: ' + e.message, 'warn');\n    }\n  });\n\n  reg('calcConvert.units', async () => {\n    const doc = await ferrum.editor.active();\n    const seed = doc && doc.selectedText && parseQuantity(doc.selectedText) ? doc.selectedText : '';\n    const text = await ferrum.window.showInputBox({ prompt: 'Convert units', value: seed, placeholder: '12 km to mi, 70 f to c, 3 hours to minutes, 2 GiB to MB' });\n    if (!text) return;\n    const q = parseQuantity(text);\n    if (!q) return ferrum.window.showMessage('Write it like \"12 km to mi\".', 'warn');\n    try {\n      const out = fmt(convertUnit(q.value, q.from, q.to), digits());\n      await deliver(q.value + ' ' + q.from + ' = ' + out + ' ' + q.to, out + ' ' + q.to);\n    } catch (e) {\n      ferrum.window.showMessage(e.message, 'warn');\n    }\n  });\n\n  reg('calcConvert.currency', async () => {\n    const def = String(ferrum.settings.get('calcConvert.defaultCurrency') || 'USD').toUpperCase();\n    const text = await ferrum.window.showInputBox({ prompt: 'Convert currency with fixed rates', placeholder: '100 USD to EUR, 250 eur in xaf, 40 gbp' });\n    if (!text) return;\n    let m = /^\\s*([\\d.,_]+)\\s*([A-Za-z]{3})\\s+(?:to|in|as|into|->)\\s+([A-Za-z]{3})\\s*$/i.exec(text);\n    if (!m) { const n = /^\\s*([\\d.,_]+)\\s*([A-Za-z]{3})\\s*$/.exec(text); if (n) m = [n[0], n[1], n[2], def]; }\n    if (!m) return ferrum.window.showMessage('Write it like \"100 USD to EUR\".', 'warn');\n    try {\n      const value = Number(m[1].replace(/[,_]/g, ''));\n      const out = convertCurrency(value, m[2], m[3], customRates());\n      const shown = out.toLocaleString('en', { maximumFractionDigits: 2 });\n      await deliver(value + ' ' + m[2].toUpperCase() + ' = ' + shown + ' ' + m[3].toUpperCase() + ' (fixed rates, not live)', shown + ' ' + m[3].toUpperCase());\n    } catch (e) {\n      ferrum.window.showMessage(e.message, 'warn');\n    }\n  });\n  reg('calcConvert.listCurrencies', async () => {\n    const t = { ...RATES, ...customRates() };\n    const pick = await ferrum.window.showQuickPick(Object.entries(t).map(([k, v]) => ({ label: k, detail: '1 USD = ' + v, code: k })), { placeholder: 'Currencies with a fixed rate. Pick one to insert its code.' });\n    if (pick) await ferrum.editor.insert(pick.code);\n  });\n\n  reg('calcConvert.bases', async () => {\n    const s = await subject();\n    if (!s) return;\n    try {\n      const v = parseInteger(s.text.trim(), 0);\n      const pick = await ferrum.window.showQuickPick(allBases(v).map(([label, value]) => ({ label: value, detail: label })), { placeholder: 'Pick a form to replace the number with' });\n      if (pick) await ferrum.editor.replace(s.range, pick.label);\n    } catch (e) {\n      ferrum.window.showMessage(e.message, 'warn');\n    }\n  });\n  reg('calcConvert.baseFrom', async () => {\n    const text = await ferrum.window.showInputBox({ prompt: 'Number and its base', placeholder: 'ff base 16, 1010 base 2, 255 (decimal), 0x1F' });\n    if (!text) return;\n    const m = /^\\s*(\\S+?)(?:\\s+(?:base|in)\\s+(\\d{1,2}))?\\s*$/i.exec(text);\n    if (!m) return;\n    try {\n      const base = m[2] ? Number(m[2]) : 0;\n      if (base && (base < 2 || base > 36)) throw new Error('The base must be from 2 to 36.');\n      const v = parseInteger(m[1], base);\n      const pick = await ferrum.window.showQuickPick(allBases(v).map(([label, value]) => ({ label: value, detail: label })), { placeholder: text + ' is...' });\n      if (pick) await ferrum.editor.insert(pick.label);\n    } catch (e) {\n      ferrum.window.showMessage(e.message, 'warn');\n    }\n  });\n};\n\nexports.deactivate = function () {};\n"},"README.md":{"encoding":"utf8","content":"# Calc and Convert\n\n## Calculator\n\nType `(12 + 8) * 3 / 4` on a line and run **Calculate Line or Selection**: the result is added as ` = 15`. **Calculate and Replace** swaps the expression for its result. It has + - * / % ^ ! parentheses, `sqrt sin cos tan ln log log2 exp abs round floor ceil min max pow hypot avg sum fact`, the constants `pi e tau phi`, hex/binary numbers (`0xff`, `0b1010`), percentages (`200 * 15%`) and `ans` for the last result. It is a small parser, never `eval`.\n\n## Units\n\n**Convert Units...** understands `12 km to mi`, `70 f to c`, `3 hours to minutes`, `2 GiB to MB`, `60 mph to km/h`: length, mass, volume, area, time, data (bits, bytes, KB and KiB), speed, pressure, energy, angle and temperature.\n\n## Currency\n\n**Convert Currency...** uses **fixed, approximate rates** built into the extension (about 50 currencies, including XAF, XOF, NGN, GHS, KES, ZAR, EUR, GBP, CAD, USD). It makes **no network request**, so the numbers are not live and may be out of date: change them in the `calcConvert.customRates` setting (for example `EUR=0.93, GBP=0.8`). Do not use it for money you will move.\n\n## Number bases\n\nSelect a number and run **Convert Number Under Cursor to Another Base...** to see it as binary, octal, decimal and hexadecimal, and pick one to replace it. **Show a Number in All Bases...** takes `ff base 16`, `1010 base 2` or `0x1F`. Big numbers are exact.\n\nNo permissions needed.\n"}}}