Przeglądaj źródła

Update to latest version with no pg pipelining (#7384)

Andrew Johnston 3 lat temu
rodzic
commit
6698a0bad5

+ 18 - 2
frameworks/JavaScript/just/README.md

@@ -1,10 +1,10 @@
 # [Just-JS](https://github.com/just-js) Benchmarking Test
 # [Just-JS](https://github.com/just-js) Benchmarking Test
 
 
-This test benchmarks the [Just-JS](https://github.com/just-js) framework. Just-JS is an in progress javascript framework for x86_64 linux.
+This test benchmarks the [Just-JS](https://github.com/just-js) framework.
 
 
 Author: Andrew Johnston <[email protected]>
 Author: Andrew Johnston <[email protected]>
 
 
-### Test Type Implementation Source Code
+## Test Type Implementation Source Code
 
 
 * [JSON] techempower.js
 * [JSON] techempower.js
 * [PLAINTEXT] techempower.js
 * [PLAINTEXT] techempower.js
@@ -15,6 +15,7 @@ Author: Andrew Johnston <[email protected]>
 * [FORTUNES] techempower.js
 * [FORTUNES] techempower.js
 
 
 ## Test URLs
 ## Test URLs
+
 ### JSON
 ### JSON
 
 
 http://localhost:8080/json
 http://localhost:8080/json
@@ -43,3 +44,18 @@ http://localhost:8080/fortunes
 
 
 http://localhost:8080/cached-world?q=
 http://localhost:8080/cached-world?q=
 
 
+## Building the Docker Image
+```bash
+docker build -t techempower:latest -f just.dockerfile .
+```
+
+## Running the TFB Postgres Docker Container
+```bash
+## docker network create -d bridge tfb
+docker run -p 5432:5432 -d --rm --name tfb-database --network tfb techempower/tfb.database.postgres:latest
+```
+
+## Running the Docker Container
+```bash
+docker run -p 8080:8080 -d --rm --name tfb-server --network tfb techempower:latest
+```

+ 1 - 1
frameworks/JavaScript/just/benchmark_config.json

@@ -25,7 +25,7 @@
         "database_os": "Linux",
         "database_os": "Linux",
         "display_name": "just-js",
         "display_name": "just-js",
         "notes": "",
         "notes": "",
-        "versus": "nodejs"
+        "versus": ""
       }
       }
     }
     }
   ]
   ]

+ 0 - 20
frameworks/JavaScript/just/config.toml

@@ -1,20 +0,0 @@
-[framework]
-name = "just"
-
-[main]
-urls.plaintext = "/plaintext"
-urls.json = "/json"
-urls.db = "/db"
-urls.query = "/query?q="
-urls.update = "/update?q="
-urls.fortune = "/fortunes"
-urls.cached_query = "/cached-world?q="
-approach = "Realistic"
-classification = "Platform"
-database = "Postgres"
-database_os = "Linux"
-os = "Linux"
-orm = "Raw"
-platform = "just-js"
-webserver = "None"
-versus = "nodejs"

+ 18 - 0
frameworks/JavaScript/just/fortunes.html

@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+  <tr>
+    <th>id</th>
+    <th>message</th>
+  </tr>
+  {{#each this}}
+  <tr>
+    <td>{{id}}</td>
+    <td>{{message}}</td>
+  </tr>
+  {{/each}}
+</table>
+</body>
+</html>

+ 15 - 22
frameworks/JavaScript/just/just.dockerfile

@@ -1,27 +1,20 @@
-FROM debian:stretch-slim AS builder
+FROM debian:buster-slim AS pre-build
 RUN apt update
 RUN apt update
+RUN apt upgrade -y
 RUN apt install -y g++ curl make tar gzip libfindbin-libs-perl
 RUN apt install -y g++ curl make tar gzip libfindbin-libs-perl
-RUN curl -L -o 0.0.2.tar.gz -L https://github.com/just-js/just/archive/0.0.2.tar.gz
-RUN tar -zxvf 0.0.2.tar.gz
-WORKDIR /just-0.0.2
-RUN make runtime
-RUN curl -L -o modules.tar.gz https://github.com/just-js/modules/archive/0.0.3.tar.gz
-RUN tar -zxvf modules.tar.gz
-RUN mv modules-0.0.3 modules
-RUN JUST_HOME=$(pwd) make -C modules/picohttp/ deps http.so
-RUN JUST_HOME=$(pwd) make -C modules/html/ html.so
 
 
-FROM debian:stretch-slim
+FROM pre-build AS builder
+WORKDIR /build
+RUN sh -c "$(curl -sSL https://raw.githubusercontent.com/just-js/just/0.1.8/install.sh)"
+RUN make -C just install
+ENV JUST_HOME=/build/just
+ENV JUST_TARGET=/build/just
 WORKDIR /app
 WORKDIR /app
-RUN mkdir -p /app/lib
-COPY lib/stringify.js lib/connection.js lib/dns.js lib/http.js lib/lookup.js lib/pg.js lib/stats.js lib/tcp.js lib/md5.js lib/monitor.js ./lib/
-COPY techempower.js spawn.js ./
-COPY --from=builder /just-0.0.2/just /bin/just
-COPY --from=builder /just-0.0.2/modules/picohttp/http.so ./
-COPY --from=builder /just-0.0.2/modules/html/html.so ./
-ENV LD_LIBRARY_PATH=/app
-ENV PGPOOL=1
+COPY techempower.js util.js tfb.config.js ./
+RUN just build --clean --cleanall --static techempower.js
 
 
-EXPOSE 8080
-
-CMD ["just", "spawn.js", "techempower.js"]
+FROM gcr.io/distroless/static:latest
+WORKDIR /app
+COPY --from=builder /app/techempower /app/techempower
+COPY fortunes.html /app/fortunes.html
+CMD ["./techempower"]

+ 0 - 360
frameworks/JavaScript/just/lib/connection.js

@@ -1,360 +0,0 @@
-const { lookup } = require('lookup.js')
-const { createClient } = require('tcp.js')
-const { md5AuthMessage, syncMessage, startupMessage, createParser, getPGError, constants } = require('pg.js')
-const { html } = just.library('html.so', 'html')
-
-const {
-  AuthenticationOk,
-  ErrorResponse,
-  RowDescription,
-  CommandComplete,
-  ParseComplete,
-  NoData,
-  ReadyForQuery
-} = constants.messageTypes
-
-const { INT4OID } = constants.fieldTypes
-
-function getMessageName (type) {
-  const code = String.fromCharCode(type)
-  let name = ''
-  Object.keys(constants.messageTypes).some(key => {
-    if (constants.messageTypes[key] === type) {
-      name = key
-      return true
-    }
-  })
-  return { type, code, name }
-}
-
-function setupSocket (sock, config) {
-  function compile (query, onComplete) {
-    const buf = new ArrayBuffer(4096)
-    const dv = new DataView(buf)
-    let len = 0
-    const fun = {
-      dv,
-      size: 0,
-      described: false,
-      buffer: new ArrayBuffer(65536),
-      messages: {
-        prepare: { start: 0, len: 0 },
-        bind: { start: 0, len: 0 },
-        exec: { start: 0, len: 0 },
-        describe: { start: 0, len: 0 },
-        flush: { start: 0, len: 0 },
-        sync: { start: 0, len: 0 }
-      },
-      paramStart: 0
-    }
-    fun.buffer.offset = 0
-    const { name, sql, params = [], formats = [], fields = [], portal = '', maxRows = 0 } = query
-    fun.call = (onComplete, syncIt = true, flushIt = false) => {
-      let off = fun.paramStart
-      // 32 bit integers only for now
-      for (let i = 0; i < params.length; i++) {
-        off += 4
-        dv.setUint32(off, params[i])
-        off += 4
-      }
-      const { bind, exec, flush, sync } = fun.messages
-      off = bind.start
-      let len = 0
-      if (flushIt) {
-        len = flush.start + flush.len - off
-      } else if (syncIt) {
-        len = sync.start + sync.len - off
-      } else {
-        len = exec.start + exec.len - off
-      }
-      const r = sock.write(buf, len, off)
-      if (r < len) {
-        just.error('short write')
-      }
-      callbacks.push(onComplete)
-    }
-    fun.append = (onComplete, syncIt = true, flushIt = false) => {
-      let off = fun.paramStart
-      // 32 bit integers only for now
-      for (let i = 0; i < params.length; i++) {
-        off += 4
-        dv.setUint32(off, params[i])
-        off += 4
-      }
-      const { bind, exec, flush, sync } = fun.messages
-      off = bind.start
-      let len = 0
-      if (flushIt) {
-        len = flush.start + flush.len - off
-      } else if (syncIt) {
-        len = sync.start + sync.len - off
-      } else {
-        len = exec.start + exec.len - off
-      }
-      fun.buffer.offset += fun.buffer.copyFrom(buf, fun.buffer.offset, len, off)
-      callbacks.push(onComplete)
-    }
-    fun.send = () => {
-      const r = sock.write(fun.buffer, fun.buffer.offset, 0)
-      if (r < len) {
-        just.error('short write')
-      }
-      fun.buffer.offset = 0
-    }
-    fun.bind = (flushIt = true, onComplete) => {
-      const { bind, flush } = fun.messages
-      sock.write(buf, bind.len, bind.start)
-      if (flushIt) {
-        sock.write(buf, flush.len, flush.start)
-      }
-      callbacks.push(onComplete)
-    }
-    fun.exec = (flushIt = true, onComplete) => {
-      const { exec, flush } = fun.messages
-      sock.write(buf, exec.len, exec.start)
-      if (flushIt) {
-        sock.write(buf, flush.len, flush.start)
-      }
-      callbacks.push(onComplete)
-    }
-    fun.prepare = (flushIt = true, onComplete) => {
-      const { prepare, flush } = fun.messages
-      sock.write(buf, prepare.len, prepare.start)
-      if (flushIt) {
-        sock.write(buf, flush.len, flush.start)
-      }
-      callbacks.push(onComplete)
-    }
-    fun.describe = (flushIt = true, onComplete) => {
-      const { describe, flush } = fun.messages
-      sock.write(buf, describe.len, describe.start)
-      if (flushIt) {
-        sock.write(buf, flush.len, flush.start)
-      }
-      callbacks.push(onComplete)
-    }
-    let off = 0
-    // Prepare Message
-    fun.messages.prepare.start = off
-    len = 1 + 4 + sql.length + 1 + name.length + 1 + 2 + (formats.length * 4)
-    dv.setUint8(off++, 80) // 'P'
-    dv.setUint32(off, len - 1)
-    off += 4
-    off += buf.writeString(name, off)
-    dv.setUint8(off++, 0)
-    off += buf.writeString(sql, off)
-    dv.setUint8(off++, 0)
-    dv.setUint16(off, formats.length)
-    off += 2
-    for (let i = 0; i < formats.length; i++) {
-      dv.setUint32(off, formats[i].oid)
-      off += 4
-    }
-    fun.messages.prepare.len = off - fun.messages.prepare.start
-    // Describe Message
-    fun.messages.describe.start = off
-    len = 7 + name.length
-    dv.setUint8(off++, 68) // 'D'
-    dv.setUint32(off, len - 1)
-    off += 4
-    dv.setUint8(off++, 83) // 'S'
-    off += buf.writeString(name, off)
-    dv.setUint8(off++, 0)
-    fun.messages.describe.len = off - fun.messages.describe.start
-
-    // Bind Message
-    fun.messages.bind.start = off
-    dv.setUint8(off++, 66) // 'B'
-    off += 4 // length - will be filled in later
-    if (portal.length) {
-      off += buf.writeString(portal, off)
-      dv.setUint8(off++, 0)
-      off += buf.writeString(name, off)
-      dv.setUint8(off++, 0)
-    } else {
-      dv.setUint8(off++, 0)
-      off += buf.writeString(name, off)
-      dv.setUint8(off++, 0)
-    }
-    dv.setUint16(off, formats.length || 0)
-    off += 2
-    for (let i = 0; i < formats.length; i++) {
-      dv.setUint16(off, formats[i].format)
-      off += 2
-    }
-    dv.setUint16(off, params.length || 0)
-    off += 2
-    fun.paramStart = off
-    for (let i = 0; i < params.length; i++) {
-      if ((formats[i] || formats[0]).format === 1) {
-        dv.setUint32(off, 4)
-        off += 4
-        dv.setUint32(off, params[i])
-        off += 4
-      } else {
-        const paramString = params[i].toString()
-        dv.setUint32(off, paramString.length)
-        off += 4
-        off += buf.writeString(paramString, off)
-      }
-    }
-    dv.setUint16(off, fields.length)
-    off += 2
-    for (let i = 0; i < fields.length; i++) {
-      dv.setUint16(off, fields[i].format)
-      off += 2
-    }
-    fun.messages.bind.len = off - fun.messages.bind.start
-    dv.setUint32(fun.messages.bind.start + 1, fun.messages.bind.len - 1)
-    // Exec Message
-    fun.messages.exec.start = off
-    len = 6 + portal.length + 4
-    dv.setUint8(off++, 69) // 'E'
-    dv.setUint32(off, len - 1)
-    off += 4
-    if (portal.length) {
-      off += buf.writeString(portal, off)
-    }
-    dv.setUint8(off++, 0)
-    dv.setUint32(off, maxRows)
-    off += 4
-    fun.messages.exec.len = off - fun.messages.exec.start
-    // Sync Message
-    fun.messages.sync.start = off
-    dv.setUint8(off++, 83) // 'S'
-    dv.setUint32(off, 4)
-    off += 4
-    fun.messages.sync.len = off - fun.messages.sync.start
-    // Flush Message
-    fun.messages.flush.start = off
-    dv.setUint8(off++, 72) // 'H'
-    dv.setUint32(off, 4)
-    off += 4
-    fun.messages.flush.len = off - fun.messages.flush.start
-    fun.size = off
-    fun.buf = buf.slice(0, off)
-    Object.assign(query, fun)
-    let readString = just.sys.readString
-    if (query.htmlEscape) {
-      readString = html.escape
-    }
-    query.getRows = () => {
-      const { buf, dv } = parser
-      const { fields } = query
-      const { start, rows } = parser.query
-      let off = start
-      const result = []
-      let i = 0
-      let j = 0
-      let row
-      for (i = 0; i < rows; i++) {
-        off += 5
-        const cols = dv.getUint16(off)
-        off += 2
-        row = Array(cols)
-        result.push(row)
-        for (j = 0; j < cols; j++) {
-          len = dv.getUint32(off)
-          const { oid, format } = (fields[j] || fields[0])
-          off += 4
-          if (format === 0) { // Non-Binary
-            if (oid === INT4OID) {
-              row[j] = parseInt(buf.readString(len, off), 10)
-            } else {
-              row[j] = readString(buf, len, off)
-            }
-          } else {
-            if (oid === INT4OID) {
-              row[j] = dv.getInt32(off)
-            } else {
-              row[j] = buf.slice(off, off + len)
-            }
-          }
-          off += len
-        }
-      }
-      return result
-    }
-    query.getResult = () => parser.getResult()
-    if (!onComplete) return query
-    fun.prepare(true, err => {
-      if (err) return onComplete(err)
-      fun.describe(true, err => {
-        if (err) return onComplete(err)
-        onComplete()
-      })
-    })
-    return query
-  }
-
-  function start (onStart) {
-    callbacks.push(onStart)
-    sock.write(startupMessage(config))
-  }
-
-  function authenticate (onAuthenticate) {
-    callbacks.push(onAuthenticate)
-    sock.write(md5AuthMessage({ user, pass, salt: parser.salt }))
-  }
-
-  function onMessage () {
-    const { type } = parser
-    if (type === CommandComplete) {
-      callbacks.shift()()
-      return
-    }
-    if (type === ReadyForQuery) {
-      if (!sock.authenticated) {
-        sock.authenticated = true
-        callbacks.shift()()
-      }
-      return
-    }
-    if (type === ErrorResponse) {
-      callbacks.shift()(new Error(getPGError(parser.errors)))
-      return
-    }
-    if (type === AuthenticationOk || type === ParseComplete || type === RowDescription || type === NoData) callbacks.shift()()
-  }
-
-  const buf = new ArrayBuffer(64 * 1024)
-  sock.authenticated = false
-  const parser = sock.parser = createParser(buf)
-  const callbacks = []
-  const { user, pass } = config
-  parser.onMessage = onMessage
-  sock.authenticate = authenticate
-  sock.sync = () => sock.write(syncMessage())
-  sock.start = start
-  sock.compile = compile
-  sock.onData = bytes => parser.parse(bytes)
-  sock.onClose = () => {
-    just.error('pg socket closed')
-  }
-  sock.getParams = () => parser.parameters
-  sock.size = () => callbacks.length
-  sock.query = parser.query
-  sock.buffer = buf
-  return sock
-}
-
-function connect (config, onPGConnect) {
-  lookup(config.hostname, (err, ip) => {
-    if (err) {
-      onPGConnect(err)
-      return
-    }
-    config.address = ip
-    const sock = createClient(config.address, config.port)
-    sock.onClose = () => {
-      just.error('pg socket closed')
-    }
-    sock.onConnect = err => {
-      onPGConnect(err, setupSocket(sock, config))
-      return sock.buffer
-    }
-    sock.connect()
-  })
-}
-
-module.exports = { connect, constants, getMessageName }

+ 0 - 193
frameworks/JavaScript/just/lib/dns.js

@@ -1,193 +0,0 @@
-const opcode = {
-  QUERY: 0,
-  IQUERY: 1,
-  STATUS: 2
-}
-
-const qtype = {
-  A: 1,
-  NS: 2,
-  MD: 3,
-  MF: 4,
-  CNAME: 5,
-  SOA: 6,
-  MB: 7,
-  MG: 8,
-  MR: 9,
-  NULL: 10,
-  WKS: 11,
-  PTR: 12,
-  HINFO: 13,
-  MINFO: 14,
-  MX: 15,
-  TXT: 16,
-  // Additional
-  AXFR: 252,
-  MAILB: 253,
-  MAILA: 254,
-  ANY: 255
-}
-
-const qclass = {
-  IN: 1,
-  CS: 2,
-  CH: 3,
-  HS: 4,
-  ANY: 255
-}
-
-const rcode = {
-  NOERROR: 0,
-  FORMAT: 1,
-  SERVER: 2,
-  NAME: 3,
-  NOTIMPL: 4,
-  REFUSED: 5
-}
-
-const types = { opcode, qtype, qclass, rcode }
-
-function readName (offset, buf, view) {
-  let name = []
-  let qnameSize = view.getUint8(offset++)
-  while (qnameSize) {
-    if ((qnameSize & 192) === 192) {
-      let off = (qnameSize - 192) << 8
-      off += view.getUint8(offset++)
-      name = name.concat(readName(off, buf, view))
-      qnameSize = 0
-    } else {
-      name.push(buf.readString(qnameSize, offset))
-      offset += qnameSize
-      qnameSize = view.getUint8(offset++)
-    }
-  }
-  return name
-}
-
-const parse = (buf, len) => {
-  const bytes = new Uint8Array(buf)
-  const view = new DataView(buf)
-  const id = view.getUint16(0)
-  const flags = view.getUint16(2)
-  const QR = (flags >> 15) & 0b1
-  const opCode = (flags >> 11) & 0b1111
-  const AA = (flags >> 10) & 0b1
-  const TC = (flags >> 9) & 0b1
-  const RD = (flags >> 8) & 0b1
-  const RA = (flags >> 7) & 0b1
-  const Z = (flags >> 4) & 0b111
-  const RCODE = flags & 0b1111
-  const qcount = view.getUint16(4)
-  const ancount = view.getUint16(6)
-  const nscount = view.getUint16(8)
-  const arcount = view.getUint16(10)
-  const question = []
-  const answer = []
-  const authority = []
-  const additional = []
-  const start = 12
-  let off = start
-  let i = off
-  let counter = qcount
-  while (counter--) {
-    let size = 0
-    const sections = []
-    while (bytes[i++]) size++
-    if (size > 0) {
-      while (off - start < size) {
-        const qnameSize = view.getUint8(off++)
-        sections.push(buf.readString(qnameSize, off))
-        off += qnameSize
-      }
-    }
-    off++
-    const qtype = view.getUint16(off)
-    off += 2
-    const qclass = view.getUint16(off)
-    off += 2
-    question.push({ qtype, qclass, name: sections })
-  }
-  counter = ancount
-  while (counter--) {
-    const next = view.getUint16(off)
-    let name
-    if ((0b1100000000000000 & next) === 0b1100000000000000) {
-      name = readName(next & 0b11111111111111, buf, view)
-      off += 2
-    } else {
-      name = readName(off, buf, view)
-      off += name.length + (name.reduce((a, v) => a + v.length, 0)) + 1
-    }
-    const qtype = view.getUint16(off)
-    off += 2
-    const qclass = view.getUint16(off)
-    off += 2
-    const ttl = view.getUint32(off)
-    off += 4
-    const rdLength = view.getUint16(off)
-    off += 2
-    if (qtype === 5) {
-      const cname = readName(off, buf, view)
-      answer.push({ name, cname, qtype, qclass, ttl })
-    } else if (qtype === 1) {
-      answer.push({ name, qtype, qclass, ttl, ip: bytes.slice(off, off + rdLength) })
-    }
-    off += rdLength
-  }
-  return { bytes: bytes.slice(0, len), qcount, nscount, ancount, arcount, id, flags, QR, opCode, AA, TC, RD, RA, Z, RCODE, question, answer, authority, additional }
-}
-
-const create = (domain, buf, id, qtype = 1, qclass = 1) => {
-  const view = new DataView(buf)
-  const bytes = new Uint8Array(buf)
-  view.setUint16(0, id)
-  view.setUint16(2, 0b0000000101000000)
-  view.setUint16(4, 1)
-  view.setUint16(6, 0)
-  view.setUint16(8, 0)
-  view.setUint16(10, 0)
-  let off = 12
-  const parts = domain.split('.')
-  for (const part of parts) {
-    view.setUint8(off++, part.length)
-    buf.writeString(part, off)
-    off += part.length
-  }
-  bytes[off++] = 0
-  view.setUint16(off, qtype)
-  off += 2
-  view.setUint16(off, qclass)
-  off += 2
-  return off
-}
-
-const qtypes = {}
-Object.keys(types.qtype).forEach(k => {
-  qtypes[types.qtype[k]] = k
-})
-const qclasses = {}
-Object.keys(types.qclass).forEach(k => {
-  qclasses[types.qclass[k]] = k
-})
-const opcodes = {}
-Object.keys(types.opcode).forEach(k => {
-  opcodes[types.opcode[k]] = k
-})
-const rcodes = {}
-Object.keys(types.rcode).forEach(k => {
-  rcodes[types.rcode[k]] = k
-})
-
-function getFlags (message) {
-  const flags = []
-  if (message.QR) flags.push('qr')
-  if (message.AA) flags.push('aa')
-  if (message.TC) flags.push('tc')
-  if (message.RD) flags.push('rd')
-  if (message.RA) flags.push('ra')
-  if (message.Z) flags.push('z')
-  return flags.join(' ')
-}
-
-module.exports = { getFlags, create, parse, types, qtypes, qclasses, opcodes, rcodes }

+ 0 - 38
frameworks/JavaScript/just/lib/http.js

@@ -1,38 +0,0 @@
-const { http } = just.library('http.so', 'http')
-const { parseRequests, getRequests, getUrl } = http
-
-const free = []
-
-function createParser (buffer) {
-  if (free.length) {
-    const parser = free.shift()
-    parser.buffer.offset = 0
-    return parser
-  }
-  const answer = [0]
-  const parser = { buffer }
-  function parse (bytes, off = 0) {
-    const count = parseRequests(buffer, buffer.offset + bytes, off, answer)
-    if (count > 0) {
-      parser.onRequests(count)
-    }
-    if (answer[0] > 0) {
-      const start = buffer.offset + bytes - answer[0]
-      const len = answer[0]
-      if (start > buffer.offset) {
-        buffer.copyFrom(buffer, 0, len, start)
-      }
-      buffer.offset = len
-      return
-    }
-    buffer.offset = 0
-  }
-  buffer.offset = 0
-  parser.parse = parse
-  parser.get = count => getRequests(count)
-  parser.url = index => getUrl(index)
-  parser.free = () => free.push(parser)
-  return parser
-}
-
-module.exports = { createParser }

+ 0 - 117
frameworks/JavaScript/just/lib/lookup.js

@@ -1,117 +0,0 @@
-const { create, parse } = require('dns.js')
-const { udp, net } = just
-const { loop } = just.factory
-const { readFile, isFile } = require('fs')
-
-const dnsServer = just.env().DNS_SERVER || '127.0.0.11'
-
-function parseLine (line) {
-  const parts = line.split(/\s+/)
-  const [address, ...hosts] = parts
-  return { address, hosts }
-}
-
-const rxipv4 = /\d+\.\d+\.\d+\.\d+/
-const rxComment = /(\s+)?#.+/
-const rxName = /nameserver\s+(.+)/
-
-function readHosts () {
-  const ipv4 = {}
-  const ipv6 = {}
-  const fileName = '/etc/hosts'
-  if (!isFile(fileName)) {
-    just.error(`${fileName} not found`)
-    return { ipv4, ipv6 }
-  }
-  const hosts = readFile(fileName)
-  const lines = hosts.split('\n').filter(line => line.trim())
-  for (const line of lines) {
-    if (line.match(rxComment)) continue
-    const { address, hosts } = parseLine(line)
-    if (address.match(rxipv4)) {
-      for (const host of hosts) {
-        ipv4[host] = address
-      }
-    } else {
-      for (const host of hosts) {
-        ipv6[host] = address
-      }
-    }
-  }
-  return { ipv4, ipv6 }
-}
-
-function lookupHosts (hostname) {
-  const { ipv4 } = readHosts()
-  return ipv4[hostname]
-}
-
-function readResolv () {
-  const fileName = '/etc/resolv.conf'
-  const results = []
-  if (!isFile(fileName)) {
-    just.error(`${fileName} not found`)
-    return results
-  }
-  const resolv = readFile(fileName)
-  const lines = resolv.split('\n').filter(line => line.trim())
-  for (const line of lines) {
-    const match = line.match(rxName)
-    if (match && match.length > 1) {
-      const [, ip] = match
-      if (ip.match(rxipv4)) {
-        results.push(ip)
-      }
-    }
-  }
-  return results
-}
-
-function lookup (query = 'www.google.com', onRecord = () => {}, address = dnsServer, port = 53, buf = new ArrayBuffer(65536)) {
-  const ip = lookupHosts(query)
-  if (ip) {
-    onRecord(null, ip)
-    return
-  }
-  const ips = readResolv()
-  if (ips.length) {
-    address = ips[0]
-  }
-  const fd = net.socket(net.AF_INET, net.SOCK_DGRAM | net.SOCK_NONBLOCK, 0)
-  net.bind(fd, address, port)
-  loop.add(fd, (fd, event) => {
-    just.clearTimeout(timer)
-    const answer = []
-    const len = udp.recvmsg(fd, buf, answer)
-    if (len <= 0) {
-      onRecord(new Error('Bad Message Length'))
-      return
-    }
-    const message = parse(buf, len)
-    if (!message.answer.length) {
-      onRecord(new Error(`Address Not Found for ${query}`))
-      return
-    }
-    const { ip } = message.answer[0]
-    const result = `${ip[0]}.${ip[1]}.${ip[2]}.${ip[3]}`
-    loop.remove(fd)
-    net.close(fd)
-    onRecord(null, result)
-  })
-  const len = create(query, buf, 1)
-  const rc = udp.sendmsg(fd, buf, address, port, len)
-  if (rc === -1) {
-    const errno = just.sys.errno()
-    onRecord(new Error(`Error sending ${query} to ${address}: ${just.sys.strerror(errno)} (${errno})`))
-    loop.remove(fd)
-    net.close(fd)
-    return
-  }
-  const timer = just.setTimeout(() => {
-    onRecord(new Error(`Request timed out for ${query} at ${address}`))
-    loop.remove(fd)
-    net.close(fd)
-  }, 1000)
-}
-
-module.exports = { lookup }

+ 0 - 683
frameworks/JavaScript/just/lib/md5.js

@@ -1,683 +0,0 @@
-/**
- * [js-md5]{@link https://github.com/emn178/js-md5}
- *
- * @namespace md5
- * @version 0.7.3
- * @author Chen, Yi-Cyuan [[email protected]]
- * @copyright Chen, Yi-Cyuan 2014-2017
- * @license MIT
- */
-(function () {
-  'use strict';
-
-  var ERROR = 'input is invalid type';
-  var WINDOW = typeof window === 'object';
-  var root = WINDOW ? window : {};
-  if (root.JS_MD5_NO_WINDOW) {
-    WINDOW = false;
-  }
-  var WEB_WORKER = !WINDOW && typeof self === 'object';
-  var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
-  if (NODE_JS) {
-    root = global;
-  } else if (WEB_WORKER) {
-    root = self;
-  }
-  var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports;
-  var AMD = typeof define === 'function' && define.amd;
-  var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
-  var HEX_CHARS = '0123456789abcdef'.split('');
-  var EXTRA = [128, 32768, 8388608, -2147483648];
-  var SHIFT = [0, 8, 16, 24];
-  var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64'];
-  var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
-
-  var blocks = [], buffer8;
-  if (ARRAY_BUFFER) {
-    var buffer = new ArrayBuffer(68);
-    buffer8 = new Uint8Array(buffer);
-    blocks = new Uint32Array(buffer);
-  }
-
-  if (root.JS_MD5_NO_NODE_JS || !Array.isArray) {
-    Array.isArray = function (obj) {
-      return Object.prototype.toString.call(obj) === '[object Array]';
-    };
-  }
-
-  if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
-    ArrayBuffer.isView = function (obj) {
-      return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
-    };
-  }
-
-  /**
-   * @method hex
-   * @memberof md5
-   * @description Output hash as hex string
-   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-   * @returns {String} Hex string
-   * @example
-   * md5.hex('The quick brown fox jumps over the lazy dog');
-   * // equal to
-   * md5('The quick brown fox jumps over the lazy dog');
-   */
-  /**
-   * @method digest
-   * @memberof md5
-   * @description Output hash as bytes array
-   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-   * @returns {Array} Bytes array
-   * @example
-   * md5.digest('The quick brown fox jumps over the lazy dog');
-   */
-  /**
-   * @method array
-   * @memberof md5
-   * @description Output hash as bytes array
-   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-   * @returns {Array} Bytes array
-   * @example
-   * md5.array('The quick brown fox jumps over the lazy dog');
-   */
-  /**
-   * @method arrayBuffer
-   * @memberof md5
-   * @description Output hash as ArrayBuffer
-   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-   * @returns {ArrayBuffer} ArrayBuffer
-   * @example
-   * md5.arrayBuffer('The quick brown fox jumps over the lazy dog');
-   */
-  /**
-   * @method buffer
-   * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
-   * @memberof md5
-   * @description Output hash as ArrayBuffer
-   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-   * @returns {ArrayBuffer} ArrayBuffer
-   * @example
-   * md5.buffer('The quick brown fox jumps over the lazy dog');
-   */
-  /**
-   * @method base64
-   * @memberof md5
-   * @description Output hash as base64 string
-   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-   * @returns {String} base64 string
-   * @example
-   * md5.base64('The quick brown fox jumps over the lazy dog');
-   */
-  var createOutputMethod = function (outputType) {
-    return function (message) {
-      return new Md5(true).update(message)[outputType]();
-    };
-  };
-
-  /**
-   * @method create
-   * @memberof md5
-   * @description Create Md5 object
-   * @returns {Md5} Md5 object.
-   * @example
-   * var hash = md5.create();
-   */
-  /**
-   * @method update
-   * @memberof md5
-   * @description Create and update Md5 object
-   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-   * @returns {Md5} Md5 object.
-   * @example
-   * var hash = md5.update('The quick brown fox jumps over the lazy dog');
-   * // equal to
-   * var hash = md5.create();
-   * hash.update('The quick brown fox jumps over the lazy dog');
-   */
-  var createMethod = function () {
-    var method = createOutputMethod('hex');
-    if (NODE_JS) {
-      method = nodeWrap(method);
-    }
-    method.create = function () {
-      return new Md5();
-    };
-    method.update = function (message) {
-      return method.create().update(message);
-    };
-    for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
-      var type = OUTPUT_TYPES[i];
-      method[type] = createOutputMethod(type);
-    }
-    return method;
-  };
-
-  var nodeWrap = function (method) {
-    var crypto = eval("require('crypto')");
-    var Buffer = eval("require('buffer').Buffer");
-    var nodeMethod = function (message) {
-      if (typeof message === 'string') {
-        return crypto.createHash('md5').update(message, 'utf8').digest('hex');
-      } else {
-        if (message === null || message === undefined) {
-          throw ERROR;
-        } else if (message.constructor === ArrayBuffer) {
-          message = new Uint8Array(message);
-        }
-      }
-      if (Array.isArray(message) || ArrayBuffer.isView(message) ||
-        message.constructor === Buffer) {
-        return crypto.createHash('md5').update(new Buffer(message)).digest('hex');
-      } else {
-        return method(message);
-      }
-    };
-    return nodeMethod;
-  };
-
-  /**
-   * Md5 class
-   * @class Md5
-   * @description This is internal class.
-   * @see {@link md5.create}
-   */
-  function Md5(sharedMemory) {
-    if (sharedMemory) {
-      blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
-      blocks[4] = blocks[5] = blocks[6] = blocks[7] =
-      blocks[8] = blocks[9] = blocks[10] = blocks[11] =
-      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
-      this.blocks = blocks;
-      this.buffer8 = buffer8;
-    } else {
-      if (ARRAY_BUFFER) {
-        var buffer = new ArrayBuffer(68);
-        this.buffer8 = new Uint8Array(buffer);
-        this.blocks = new Uint32Array(buffer);
-      } else {
-        this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-      }
-    }
-    this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0;
-    this.finalized = this.hashed = false;
-    this.first = true;
-  }
-
-  /**
-   * @method update
-   * @memberof Md5
-   * @instance
-   * @description Update hash
-   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-   * @returns {Md5} Md5 object.
-   * @see {@link md5.update}
-   */
-  Md5.prototype.update = function (message) {
-    if (this.finalized) {
-      return;
-    }
-
-    var notString, type = typeof message;
-    if (type !== 'string') {
-      if (type === 'object') {
-        if (message === null) {
-          throw ERROR;
-        } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
-          message = new Uint8Array(message);
-        } else if (!Array.isArray(message)) {
-          if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {
-            throw ERROR;
-          }
-        }
-      } else {
-        throw ERROR;
-      }
-      notString = true;
-    }
-    var code, index = 0, i, length = message.length, blocks = this.blocks;
-    var buffer8 = this.buffer8;
-
-    while (index < length) {
-      if (this.hashed) {
-        this.hashed = false;
-        blocks[0] = blocks[16];
-        blocks[16] = blocks[1] = blocks[2] = blocks[3] =
-        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
-        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
-        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
-      }
-
-      if (notString) {
-        if (ARRAY_BUFFER) {
-          for (i = this.start; index < length && i < 64; ++index) {
-            buffer8[i++] = message[index];
-          }
-        } else {
-          for (i = this.start; index < length && i < 64; ++index) {
-            blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
-          }
-        }
-      } else {
-        if (ARRAY_BUFFER) {
-          for (i = this.start; index < length && i < 64; ++index) {
-            code = message.charCodeAt(index);
-            if (code < 0x80) {
-              buffer8[i++] = code;
-            } else if (code < 0x800) {
-              buffer8[i++] = 0xc0 | (code >> 6);
-              buffer8[i++] = 0x80 | (code & 0x3f);
-            } else if (code < 0xd800 || code >= 0xe000) {
-              buffer8[i++] = 0xe0 | (code >> 12);
-              buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
-              buffer8[i++] = 0x80 | (code & 0x3f);
-            } else {
-              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
-              buffer8[i++] = 0xf0 | (code >> 18);
-              buffer8[i++] = 0x80 | ((code >> 12) & 0x3f);
-              buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
-              buffer8[i++] = 0x80 | (code & 0x3f);
-            }
-          }
-        } else {
-          for (i = this.start; index < length && i < 64; ++index) {
-            code = message.charCodeAt(index);
-            if (code < 0x80) {
-              blocks[i >> 2] |= code << SHIFT[i++ & 3];
-            } else if (code < 0x800) {
-              blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
-              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
-            } else if (code < 0xd800 || code >= 0xe000) {
-              blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
-              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
-              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
-            } else {
-              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
-              blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
-              blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
-              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
-              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
-            }
-          }
-        }
-      }
-      this.lastByteIndex = i;
-      this.bytes += i - this.start;
-      if (i >= 64) {
-        this.start = i - 64;
-        this.hash();
-        this.hashed = true;
-      } else {
-        this.start = i;
-      }
-    }
-    if (this.bytes > 4294967295) {
-      this.hBytes += this.bytes / 4294967296 << 0;
-      this.bytes = this.bytes % 4294967296;
-    }
-    return this;
-  };
-
-  Md5.prototype.finalize = function () {
-    if (this.finalized) {
-      return;
-    }
-    this.finalized = true;
-    var blocks = this.blocks, i = this.lastByteIndex;
-    blocks[i >> 2] |= EXTRA[i & 3];
-    if (i >= 56) {
-      if (!this.hashed) {
-        this.hash();
-      }
-      blocks[0] = blocks[16];
-      blocks[16] = blocks[1] = blocks[2] = blocks[3] =
-      blocks[4] = blocks[5] = blocks[6] = blocks[7] =
-      blocks[8] = blocks[9] = blocks[10] = blocks[11] =
-      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
-    }
-    blocks[14] = this.bytes << 3;
-    blocks[15] = this.hBytes << 3 | this.bytes >>> 29;
-    this.hash();
-  };
-
-  Md5.prototype.hash = function () {
-    var a, b, c, d, bc, da, blocks = this.blocks;
-
-    if (this.first) {
-      a = blocks[0] - 680876937;
-      a = (a << 7 | a >>> 25) - 271733879 << 0;
-      d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708;
-      d = (d << 12 | d >>> 20) + a << 0;
-      c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375;
-      c = (c << 17 | c >>> 15) + d << 0;
-      b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209;
-      b = (b << 22 | b >>> 10) + c << 0;
-    } else {
-      a = this.h0;
-      b = this.h1;
-      c = this.h2;
-      d = this.h3;
-      a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936;
-      a = (a << 7 | a >>> 25) + b << 0;
-      d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586;
-      d = (d << 12 | d >>> 20) + a << 0;
-      c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819;
-      c = (c << 17 | c >>> 15) + d << 0;
-      b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330;
-      b = (b << 22 | b >>> 10) + c << 0;
-    }
-
-    a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897;
-    a = (a << 7 | a >>> 25) + b << 0;
-    d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426;
-    d = (d << 12 | d >>> 20) + a << 0;
-    c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341;
-    c = (c << 17 | c >>> 15) + d << 0;
-    b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983;
-    b = (b << 22 | b >>> 10) + c << 0;
-    a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416;
-    a = (a << 7 | a >>> 25) + b << 0;
-    d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417;
-    d = (d << 12 | d >>> 20) + a << 0;
-    c += (b ^ (d & (a ^ b))) + blocks[10] - 42063;
-    c = (c << 17 | c >>> 15) + d << 0;
-    b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162;
-    b = (b << 22 | b >>> 10) + c << 0;
-    a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682;
-    a = (a << 7 | a >>> 25) + b << 0;
-    d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101;
-    d = (d << 12 | d >>> 20) + a << 0;
-    c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290;
-    c = (c << 17 | c >>> 15) + d << 0;
-    b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329;
-    b = (b << 22 | b >>> 10) + c << 0;
-    a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510;
-    a = (a << 5 | a >>> 27) + b << 0;
-    d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632;
-    d = (d << 9 | d >>> 23) + a << 0;
-    c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713;
-    c = (c << 14 | c >>> 18) + d << 0;
-    b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302;
-    b = (b << 20 | b >>> 12) + c << 0;
-    a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691;
-    a = (a << 5 | a >>> 27) + b << 0;
-    d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083;
-    d = (d << 9 | d >>> 23) + a << 0;
-    c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335;
-    c = (c << 14 | c >>> 18) + d << 0;
-    b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848;
-    b = (b << 20 | b >>> 12) + c << 0;
-    a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438;
-    a = (a << 5 | a >>> 27) + b << 0;
-    d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690;
-    d = (d << 9 | d >>> 23) + a << 0;
-    c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961;
-    c = (c << 14 | c >>> 18) + d << 0;
-    b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501;
-    b = (b << 20 | b >>> 12) + c << 0;
-    a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467;
-    a = (a << 5 | a >>> 27) + b << 0;
-    d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784;
-    d = (d << 9 | d >>> 23) + a << 0;
-    c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473;
-    c = (c << 14 | c >>> 18) + d << 0;
-    b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734;
-    b = (b << 20 | b >>> 12) + c << 0;
-    bc = b ^ c;
-    a += (bc ^ d) + blocks[5] - 378558;
-    a = (a << 4 | a >>> 28) + b << 0;
-    d += (bc ^ a) + blocks[8] - 2022574463;
-    d = (d << 11 | d >>> 21) + a << 0;
-    da = d ^ a;
-    c += (da ^ b) + blocks[11] + 1839030562;
-    c = (c << 16 | c >>> 16) + d << 0;
-    b += (da ^ c) + blocks[14] - 35309556;
-    b = (b << 23 | b >>> 9) + c << 0;
-    bc = b ^ c;
-    a += (bc ^ d) + blocks[1] - 1530992060;
-    a = (a << 4 | a >>> 28) + b << 0;
-    d += (bc ^ a) + blocks[4] + 1272893353;
-    d = (d << 11 | d >>> 21) + a << 0;
-    da = d ^ a;
-    c += (da ^ b) + blocks[7] - 155497632;
-    c = (c << 16 | c >>> 16) + d << 0;
-    b += (da ^ c) + blocks[10] - 1094730640;
-    b = (b << 23 | b >>> 9) + c << 0;
-    bc = b ^ c;
-    a += (bc ^ d) + blocks[13] + 681279174;
-    a = (a << 4 | a >>> 28) + b << 0;
-    d += (bc ^ a) + blocks[0] - 358537222;
-    d = (d << 11 | d >>> 21) + a << 0;
-    da = d ^ a;
-    c += (da ^ b) + blocks[3] - 722521979;
-    c = (c << 16 | c >>> 16) + d << 0;
-    b += (da ^ c) + blocks[6] + 76029189;
-    b = (b << 23 | b >>> 9) + c << 0;
-    bc = b ^ c;
-    a += (bc ^ d) + blocks[9] - 640364487;
-    a = (a << 4 | a >>> 28) + b << 0;
-    d += (bc ^ a) + blocks[12] - 421815835;
-    d = (d << 11 | d >>> 21) + a << 0;
-    da = d ^ a;
-    c += (da ^ b) + blocks[15] + 530742520;
-    c = (c << 16 | c >>> 16) + d << 0;
-    b += (da ^ c) + blocks[2] - 995338651;
-    b = (b << 23 | b >>> 9) + c << 0;
-    a += (c ^ (b | ~d)) + blocks[0] - 198630844;
-    a = (a << 6 | a >>> 26) + b << 0;
-    d += (b ^ (a | ~c)) + blocks[7] + 1126891415;
-    d = (d << 10 | d >>> 22) + a << 0;
-    c += (a ^ (d | ~b)) + blocks[14] - 1416354905;
-    c = (c << 15 | c >>> 17) + d << 0;
-    b += (d ^ (c | ~a)) + blocks[5] - 57434055;
-    b = (b << 21 | b >>> 11) + c << 0;
-    a += (c ^ (b | ~d)) + blocks[12] + 1700485571;
-    a = (a << 6 | a >>> 26) + b << 0;
-    d += (b ^ (a | ~c)) + blocks[3] - 1894986606;
-    d = (d << 10 | d >>> 22) + a << 0;
-    c += (a ^ (d | ~b)) + blocks[10] - 1051523;
-    c = (c << 15 | c >>> 17) + d << 0;
-    b += (d ^ (c | ~a)) + blocks[1] - 2054922799;
-    b = (b << 21 | b >>> 11) + c << 0;
-    a += (c ^ (b | ~d)) + blocks[8] + 1873313359;
-    a = (a << 6 | a >>> 26) + b << 0;
-    d += (b ^ (a | ~c)) + blocks[15] - 30611744;
-    d = (d << 10 | d >>> 22) + a << 0;
-    c += (a ^ (d | ~b)) + blocks[6] - 1560198380;
-    c = (c << 15 | c >>> 17) + d << 0;
-    b += (d ^ (c | ~a)) + blocks[13] + 1309151649;
-    b = (b << 21 | b >>> 11) + c << 0;
-    a += (c ^ (b | ~d)) + blocks[4] - 145523070;
-    a = (a << 6 | a >>> 26) + b << 0;
-    d += (b ^ (a | ~c)) + blocks[11] - 1120210379;
-    d = (d << 10 | d >>> 22) + a << 0;
-    c += (a ^ (d | ~b)) + blocks[2] + 718787259;
-    c = (c << 15 | c >>> 17) + d << 0;
-    b += (d ^ (c | ~a)) + blocks[9] - 343485551;
-    b = (b << 21 | b >>> 11) + c << 0;
-
-    if (this.first) {
-      this.h0 = a + 1732584193 << 0;
-      this.h1 = b - 271733879 << 0;
-      this.h2 = c - 1732584194 << 0;
-      this.h3 = d + 271733878 << 0;
-      this.first = false;
-    } else {
-      this.h0 = this.h0 + a << 0;
-      this.h1 = this.h1 + b << 0;
-      this.h2 = this.h2 + c << 0;
-      this.h3 = this.h3 + d << 0;
-    }
-  };
-
-  /**
-   * @method hex
-   * @memberof Md5
-   * @instance
-   * @description Output hash as hex string
-   * @returns {String} Hex string
-   * @see {@link md5.hex}
-   * @example
-   * hash.hex();
-   */
-  Md5.prototype.hex = function () {
-    this.finalize();
-
-    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
-
-    return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
-      HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
-      HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
-      HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
-      HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
-      HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
-      HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
-      HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
-      HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
-      HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
-      HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
-      HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
-      HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
-      HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
-      HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
-      HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F];
-  };
-
-  /**
-   * @method toString
-   * @memberof Md5
-   * @instance
-   * @description Output hash as hex string
-   * @returns {String} Hex string
-   * @see {@link md5.hex}
-   * @example
-   * hash.toString();
-   */
-  Md5.prototype.toString = Md5.prototype.hex;
-
-  /**
-   * @method digest
-   * @memberof Md5
-   * @instance
-   * @description Output hash as bytes array
-   * @returns {Array} Bytes array
-   * @see {@link md5.digest}
-   * @example
-   * hash.digest();
-   */
-  Md5.prototype.digest = function () {
-    this.finalize();
-
-    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
-    return [
-      h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF,
-      h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF,
-      h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF,
-      h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF
-    ];
-  };
-
-  /**
-   * @method array
-   * @memberof Md5
-   * @instance
-   * @description Output hash as bytes array
-   * @returns {Array} Bytes array
-   * @see {@link md5.array}
-   * @example
-   * hash.array();
-   */
-  Md5.prototype.array = Md5.prototype.digest;
-
-  /**
-   * @method arrayBuffer
-   * @memberof Md5
-   * @instance
-   * @description Output hash as ArrayBuffer
-   * @returns {ArrayBuffer} ArrayBuffer
-   * @see {@link md5.arrayBuffer}
-   * @example
-   * hash.arrayBuffer();
-   */
-  Md5.prototype.arrayBuffer = function () {
-    this.finalize();
-
-    var buffer = new ArrayBuffer(16);
-    var blocks = new Uint32Array(buffer);
-    blocks[0] = this.h0;
-    blocks[1] = this.h1;
-    blocks[2] = this.h2;
-    blocks[3] = this.h3;
-    return buffer;
-  };
-
-  /**
-   * @method buffer
-   * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
-   * @memberof Md5
-   * @instance
-   * @description Output hash as ArrayBuffer
-   * @returns {ArrayBuffer} ArrayBuffer
-   * @see {@link md5.buffer}
-   * @example
-   * hash.buffer();
-   */
-  Md5.prototype.buffer = Md5.prototype.arrayBuffer;
-
-  /**
-   * @method base64
-   * @memberof Md5
-   * @instance
-   * @description Output hash as base64 string
-   * @returns {String} base64 string
-   * @see {@link md5.base64}
-   * @example
-   * hash.base64();
-   */
-  Md5.prototype.base64 = function () {
-    var v1, v2, v3, base64Str = '', bytes = this.array();
-    for (var i = 0; i < 15;) {
-      v1 = bytes[i++];
-      v2 = bytes[i++];
-      v3 = bytes[i++];
-      base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
-        BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] +
-        BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] +
-        BASE64_ENCODE_CHAR[v3 & 63];
-    }
-    v1 = bytes[i];
-    base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
-      BASE64_ENCODE_CHAR[(v1 << 4) & 63] +
-      '==';
-    return base64Str;
-  };
-
-  var exports = createMethod();
-
-  if (COMMON_JS) {
-    module.exports = exports;
-  } else {
-    /**
-     * @method md5
-     * @description Md5 hash function, export to global in browsers.
-     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
-     * @returns {String} md5 hashes
-     * @example
-     * md5(''); // d41d8cd98f00b204e9800998ecf8427e
-     * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6
-     * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0
-     *
-     * // It also supports UTF-8 encoding
-     * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07
-     *
-     * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`
-     * md5([]); // d41d8cd98f00b204e9800998ecf8427e
-     * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e
-     */
-    root.md5 = exports;
-    if (AMD) {
-      define(function () {
-        return exports;
-      });
-    }
-  }
-})();

+ 0 - 125
frameworks/JavaScript/just/lib/monitor.js

@@ -1,125 +0,0 @@
-const { fs, sys, net } = just
-
-function readStat (pid = sys.pid()) {
-  const buf = new ArrayBuffer(4096)
-  const path = `/proc/${pid}/stat`
-  const fd = fs.open(path)
-  net.seek(fd, 0, net.SEEK_SET)
-  let bytes = net.read(fd, buf)
-  const parts = []
-  while (bytes > 0) {
-    parts.push(buf.readString(bytes))
-    bytes = net.read(fd, buf)
-  }
-  const fields = parts.join('').split(' ')
-  const comm = fields[1]
-  const state = fields[2]
-  const [
-    ppid,
-    pgrp,
-    session,
-    ttyNr,
-    tpgid,
-    flags,
-    minflt,
-    cminflt,
-    majflt,
-    cmajflt,
-    utime,
-    stime,
-    cutime,
-    cstime,
-    priority,
-    nice,
-    numThreads,
-    itrealvalue,
-    starttime,
-    vsize,
-    rssPages,
-    rsslim,
-    startcode,
-    endcode,
-    startstack,
-    kstkesp,
-    kstkeip,
-    signal,
-    blocked,
-    sigignore,
-    sigcatch,
-    wchan,
-    nswap,
-    cnswap,
-    exitSignal,
-    processor,
-    rtPriority,
-    policy,
-    delayacctBlkioTicks,
-    guestTime,
-    cguestTime,
-    startData,
-    endData,
-    startBrk,
-    argStart,
-    argEnd,
-    envStart,
-    envEnd,
-    exitCode
-  ] = fields.slice(3).map(v => Number(v))
-  net.close(fd)
-  return {
-    pid,
-    comm,
-    state,
-    ppid,
-    pgrp,
-    session,
-    ttyNr,
-    tpgid,
-    flags,
-    minflt,
-    cminflt,
-    majflt,
-    cmajflt,
-    utime,
-    stime,
-    cutime,
-    cstime,
-    priority,
-    nice,
-    numThreads,
-    itrealvalue,
-    starttime,
-    vsize,
-    rssPages,
-    rsslim,
-    startcode,
-    endcode,
-    startstack,
-    kstkesp,
-    kstkeip,
-    signal,
-    blocked,
-    sigignore,
-    sigcatch,
-    wchan,
-    nswap,
-    cnswap,
-    exitSignal,
-    processor,
-    rtPriority,
-    policy,
-    delayacctBlkioTicks,
-    guestTime,
-    cguestTime,
-    startData,
-    endData,
-    startBrk,
-    argStart,
-    argEnd,
-    envStart,
-    envEnd,
-    exitCode
-  }
-}
-
-module.exports = { readStat }

+ 0 - 350
frameworks/JavaScript/just/lib/pg.js

@@ -1,350 +0,0 @@
-const md5 = require('md5.js')
-
-function syncMessage () {
-  const len = 5
-  const buf = new ArrayBuffer(len)
-  const dv = new DataView(buf)
-  dv.setUint8(0, 83)
-  dv.setUint32(1, 4)
-  return buf
-}
-
-function startupMessage ({ user, database, parameters = [] }) {
-  let len = 8 + 4 + 1 + user.length + 1 + 8 + 1 + database.length + 2
-  for (let i = 0; i < parameters.length; i++) {
-    const { name, value } = parameters[i]
-    len += (name.length + 1 + value.length + 1)
-  }
-  const buf = new ArrayBuffer(len)
-  const dv = new DataView(buf)
-  let off = 0
-  dv.setInt32(0, 0)
-  off += 4
-  // 0x00030000 = 3.0
-  dv.setInt32(4, 196608)
-  off += 4
-
-  off += buf.writeString('user', off)
-  dv.setUint8(off++, 0)
-  off += buf.writeString(user, off)
-  dv.setUint8(off++, 0)
-
-  off += buf.writeString('database', off)
-  dv.setUint8(off++, 0)
-  off += buf.writeString(database, off)
-  dv.setUint8(off++, 0)
-
-  for (let i = 0; i < parameters.length; i++) {
-    const { name, value } = parameters[i]
-    off += buf.writeString(name, off)
-    dv.setUint8(off++, 0)
-    off += buf.writeString(value, off)
-    dv.setUint8(off++, 0)
-  }
-  dv.setUint8(off++, 0)
-  dv.setInt32(0, off)
-  return buf
-}
-
-function md5AuthMessage ({ user, pass, salt }) {
-  const token = `${pass}${user}`
-  let hash = md5(token)
-  const plain = new ArrayBuffer(36)
-  plain.writeString(`md5${hash}`, 0)
-  const plain2 = new ArrayBuffer(36)
-  plain2.copyFrom(plain, 0, 32, 3)
-  plain2.copyFrom(salt, 32, 4)
-  hash = `md5${md5(plain2)}`
-  const len = hash.length + 5
-  let off = 0
-  const buf = new ArrayBuffer(len + 1)
-  const dv = new DataView(buf)
-  dv.setUint8(off++, 112)
-  dv.setUint32(off, len)
-  off += 4
-  off += buf.writeString(hash, off)
-  dv.setUint8(off++, 0)
-  return buf
-}
-
-function createParser (buf) {
-  let nextRow = 0
-  let parseNext = 0
-  let parameters = {}
-  const query = { start: 0, end: 0, rows: 0, running: false }
-
-  if (freeList.length) return freeList.shift()
-
-  function onDataRow (len, off) {
-    // D = DataRow
-    nextRow++
-    return off + len - 4
-  }
-
-  function onCommandComplete (len, off) {
-    // C = CommandComplete
-    query.end = off
-    query.rows = nextRow
-    query.running = false
-    off += len - 4
-    nextRow = 0
-    parser.onMessage()
-    return off
-  }
-
-  function onRowDescripton (len, off) {
-    // T = RowDescription
-    const fieldCount = dv.getInt16(off)
-    off += 2
-    fields.length = 0
-    for (let i = 0; i < fieldCount; i++) {
-      const name = readCString(buf, u8, off)
-      off += name.length + 1
-      const tid = dv.getInt32(off)
-      off += 4
-      const attrib = dv.getInt16(off)
-      off += 2
-      const oid = dv.getInt32(off)
-      off += 4
-      const size = dv.getInt16(off)
-      off += 2
-      const mod = dv.getInt32(off)
-      off += 4
-      const format = dv.getInt16(off)
-      off += 2
-      fields.push({ name, tid, attrib, oid, size, mod, format })
-    }
-    parser.onMessage()
-    return off
-  }
-
-  function onAuthenticationOk (len, off) {
-    // R = AuthenticationOk
-    const method = dv.getInt32(off)
-    off += 4
-    if (method === constants.AuthenticationMD5Password) {
-      parser.salt = buf.slice(off, off + 4)
-      off += 4
-      parser.onMessage()
-    }
-    return off
-  }
-
-  function onErrorResponse (len, off) {
-    // E = ErrorResponse
-    errors.length = 0
-    let fieldType = u8[off++]
-    while (fieldType !== 0) {
-      const val = readCString(buf, u8, off)
-      errors.push({ type: fieldType, val })
-      off += (val.length + 1)
-      fieldType = u8[off++]
-    }
-    parser.onMessage()
-    return off
-  }
-
-  function onParameterStatus (len, off) {
-    // S = ParameterStatus
-    const key = readCString(buf, u8, off)
-    off += (key.length + 1)
-    const val = readCString(buf, u8, off)
-    off += val.length + 1
-    parameters[key] = val
-    return off
-  }
-
-  function onParameterDescription (len, off) {
-    // t = ParameterDescription
-    const nparams = dv.getInt16(off)
-    parser.params = []
-    off += 2
-    for (let i = 0; i < nparams; i++) {
-      parser.params.push(dv.getUint32(off))
-      off += 4
-    }
-    return off
-  }
-
-  function onParseComplete (len, off) {
-    // 1 = ParseComplete
-    off += len - 4
-    parser.onMessage()
-    return off
-  }
-
-  function onBindComplete (len, off) {
-    // 2 = BindComplete
-    off += len - 4
-    parser.onMessage()
-    query.rows = 0
-    query.start = query.end = off
-    query.running = true
-    return off
-  }
-
-  function onReadyForQuery (len, off) {
-    // Z = ReadyForQuery
-    parser.status = u8[off]
-    parser.onMessage()
-    off += len - 4
-    return off
-  }
-
-  function onBackendKeyData (len, off) {
-    // K = BackendKeyData
-    parser.pid = dv.getUint32(off)
-    off += 4
-    parser.key = dv.getUint32(off)
-    off += 4
-    parser.onMessage()
-    return off
-  }
-
-  function parse (bytesRead) {
-    let type
-    let len
-    let off = parseNext
-    const end = buf.offset + bytesRead
-    while (off < end) {
-      const remaining = end - off
-      let want = 5
-      if (remaining < want) {
-        if (byteLength - off < 1024) {
-          if (query.running) {
-            const queryLen = off - query.start + remaining
-            buf.copyFrom(buf, 0, queryLen, query.start)
-            buf.offset = queryLen
-            parseNext = off - query.start
-            query.start = 0
-            return
-          }
-          buf.copyFrom(buf, 0, remaining, off)
-          buf.offset = remaining
-          parseNext = 0
-          return
-        }
-        buf.offset = off + remaining
-        parseNext = off
-        return
-      }
-      type = parser.type = dv.getUint8(off)
-      len = parser.len = dv.getUint32(off + 1)
-      want = len + 1
-      if (remaining < want) {
-        if (byteLength - off < 1024) {
-          if (query.running) {
-            const queryLen = off - query.start + remaining
-            buf.copyFrom(buf, 0, queryLen, query.start)
-            buf.offset = queryLen
-            parseNext = off - query.start
-            query.start = 0
-            return
-          }
-          buf.copyFrom(buf, 0, remaining, off)
-          buf.offset = remaining
-          parseNext = 0
-          return
-        }
-        buf.offset = off + remaining
-        parseNext = off
-        return
-      }
-      off += 5
-      off = (V[type] || V[0])(len, off)
-    }
-    parseNext = buf.offset = 0
-  }
-
-  function getResult () {
-    return readCString(buf, u8, parseNext)
-  }
-
-  function onDefault (len, off) {
-    off += len - 4
-    parser.onMessage()
-    return off
-  }
-
-  function free () {
-    parser.fields.length = 0
-    parser.errors.length = 0
-    parameters = parser.parameters = {}
-    nextRow = 0
-    parseNext = 0
-    query.start = query.end = query.rows = 0
-    query.running = false
-    freeList.push(parser)
-  }
-
-  const { messageTypes } = constants
-  const dv = new DataView(buf)
-  const u8 = new Uint8Array(buf)
-  const byteLength = buf.byteLength
-  const fields = []
-  const errors = []
-  const V = {
-    [messageTypes.AuthenticationOk]: onAuthenticationOk,
-    [messageTypes.ErrorResponse]: onErrorResponse,
-    [messageTypes.RowDescription]: onRowDescripton,
-    [messageTypes.CommandComplete]: onCommandComplete,
-    [messageTypes.ParseComplete]: onParseComplete,
-    [messageTypes.BindComplete]: onBindComplete,
-    [messageTypes.ReadyForQuery]: onReadyForQuery,
-    [messageTypes.BackendKeyData]: onBackendKeyData,
-    [messageTypes.ParameterStatus]: onParameterStatus,
-    [messageTypes.ParameterDescription]: onParameterDescription,
-    [messageTypes.DataRow]: onDataRow,
-    0: onDefault
-  }
-  const parser = {
-    buf,
-    dv,
-    fields,
-    parameters,
-    type: 0,
-    len: 0,
-    errors,
-    getResult,
-    parse,
-    free,
-    query
-  }
-  return parser
-}
-
-function readCString (buf, u8, off) {
-  const start = off
-  while (u8[off] !== 0) off++
-  return buf.readString(off - start, start)
-}
-
-function getPGError (errors) {
-  return errors.filter(v => v.type === 77)[0].val
-}
-
-const constants = {
-  AuthenticationMD5Password: 5,
-  fieldTypes: {
-    INT4OID: 23,
-    VARCHAROID: 1043
-  },
-  messageTypes: {
-    AuthenticationOk: 82,
-    ErrorResponse: 69,
-    RowDescription: 84,
-    CommandComplete: 67,
-    ParseComplete: 49,
-    BindComplete: 50,
-    ReadyForQuery: 90,
-    BackendKeyData: 75,
-    ParameterStatus: 83,
-    ParameterDescription: 116,
-    DataRow: 68,
-    NoData: 110
-  }
-}
-
-const freeList = []
-
-module.exports = { createParser, syncMessage, startupMessage, md5AuthMessage, getPGError, constants }

+ 0 - 28
frameworks/JavaScript/just/lib/stats.js

@@ -1,28 +0,0 @@
-function start () {
-  function onTime () {
-    stats.time = (new Date()).toUTCString()
-  }
-  const stats = { conn: 0, qps: 0, rps: 0, time: 0 }
-  just.setInterval(() => {
-    if (just.buffer) {
-      u32 = new Uint32Array(just.buffer)
-    }
-    if (u32) {
-      Atomics.exchange(u32, 0, stats.rps)
-    } else {
-      const { conn, qps, rps, clients } = stats
-      const { user, system } = just.cpuUsage()
-      const { rss } = just.memoryUsage()
-      const rpspc = ((rps / (user + system)) || 0)
-      just.error(`conn ${conn} qps ${qps} rps ${rps} clients ${clients} mem ${rss} cpu (${user.toFixed(2)}/${system.toFixed(2)}) ${(user + system).toFixed(2)} rps/core ${rpspc.toFixed(2)}`)
-    }
-    stats.qps = stats.rps = 0
-  }, 1000)
-  just.setInterval(onTime, 100)
-  onTime()
-  return stats
-}
-
-let u32
-
-module.exports = { start }

+ 0 - 103
frameworks/JavaScript/just/lib/stringify.js

@@ -1,103 +0,0 @@
-// lifted from here: https://github.com/lucagez/slow-json-stringify
-
-var _prepare = function(e) {
-  var r = JSON.stringify(e, function(e, r) {
-      return r.isSJS ? r.type + "__sjs" : r
-  });
-  return {
-      preparedString: r,
-      preparedSchema: JSON.parse(r)
-  }
-},
-_find = function(path) {
-  for (var length = path.length, str = "obj", i = 0; i < length; i++) str = str.replace(/^/, "("), str += " || {})." + path[i];
-  return just.vm.runScript("((obj) => " + str + ")")
-},
-_makeArraySerializer = function(e) {
-  return e instanceof Function ? function(r) {
-      for (var n = "", t = r.length, a = 0; a < t - 1; a++) n += e(r[a]) + ",";
-      return "[" + (n += e(r[t - 1])) + "]"
-  } : function(e) {
-      return JSON.stringify(e)
-  }
-},
-TYPES = ["number", "string", "boolean", "array", "null"],
-attr = function(e, r) {
-  if (!TYPES.includes(e)) throw new Error('Expected one of: "number", "string", "boolean", "null". received "' + e + '" instead');
-  var n = r || function(e) {
-      return e
-  };
-  return {
-      isSJS: !0,
-      type: e,
-      serializer: "array" === e ? _makeArraySerializer(r) : n
-  }
-},
-defaultRegex = new RegExp('\\n|\\r|\\t|\\"|\\\\', "gm"),
-escape = function(e) {
-  return void 0 === e && (e = defaultRegex),
-      function(r) {
-          return r.replace(e, function(e) {
-              return "\\" + e
-          })
-      }
-},
-_makeQueue = function(e, r) {
-  var n = [];
-  return function e(t, a) {
-      if (void 0 === a && (a = []), !/__sjs/.test(t)) return Object.keys(t).map(function(r) {
-          return e(t[r], a.concat([r]))
-      });
-      var i = Array.from(a),
-          u = _find(i),
-          s = u(r);
-      n.push({
-          serializer: s.serializer,
-          find: u,
-          name: a[a.length - 1]
-      })
-  }(e), n
-},
-_makeChunks = function(e, r) {
-  return e.replace(/"\w+__sjs"/gm, function(e) {
-      return /string/.test(e) ? '"__par__"' : "__par__"
-  }).split("__par__").map(function(e, n, t) {
-      var a = '("' + (r[n] || {}).name + '":("?))$',
-          i = "(,?)" + a,
-          u = /^("}|})/.test(t[n + 1] || ""),
-          s = new RegExp(u ? i : a),
-          f = /^(\"\,|\,|\")/;
-      return {
-          flag: !1,
-          pure: e,
-          prevUndef: e.replace(f, ""),
-          isUndef: e.replace(s, ""),
-          bothUndef: e.replace(f, "").replace(s, "")
-      }
-  })
-},
-_select = function(e) {
-  return function(r, n) {
-      var t = e[n];
-      return void 0 !== r ? t.flag ? t.prevUndef + r : t.pure + r : (e[n + 1].flag = !0, t.flag ? t.bothUndef : t.isUndef)
-  }
-},
-sjs = function(e) {
-  var r = _prepare(e),
-      n = r.preparedString,
-      t = _makeQueue(r.preparedSchema, e),
-      a = _makeChunks(n, t),
-      i = _select(a),
-      u = t.length;
-  return function(e) {
-      for (var r = "", n = 0; n !== u;) {
-          var s = t[n],
-              f = s.serializer,
-              p = (0, s.find)(e);
-          r += i(f(p), n), n += 1
-      }
-      var o = a[a.length - 1];
-      return r + (o.flag ? o.prevUndef : o.pure)
-  }
-};
-exports.sjs = sjs, exports.attr = attr, exports.escape = escape;

+ 0 - 178
frameworks/JavaScript/just/lib/tcp.js

@@ -1,178 +0,0 @@
-
-const { sys, net } = just
-const { EPOLLIN, EPOLLERR, EPOLLHUP, EPOLLOUT } = just.loop
-const { IPPROTO_TCP, O_NONBLOCK, TCP_NODELAY, SO_KEEPALIVE, SOMAXCONN, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR, SO_REUSEPORT, SOCK_NONBLOCK, SO_ERROR } = net
-
-const { loop } = just.factory
-
-const readableMask = EPOLLIN | EPOLLERR | EPOLLHUP
-const readableWritableMask = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT
-
-function createServer (host = '127.0.0.1', port = 3000) {
-  const server = { host, port }
-  const sockets = {}
-
-  function closeSocket (sock) {
-    const { fd } = sock
-    sock.onClose && sock.onClose(sock)
-    delete sockets[fd]
-    loop.remove(fd)
-    net.close(fd)
-  }
-
-  function onConnect (fd, event) {
-    if (event & EPOLLERR || event & EPOLLHUP) {
-      return closeSocket({ fd })
-    }
-    const clientfd = net.accept(fd)
-    const socket = sockets[clientfd] = { fd: clientfd }
-    net.setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY, 0)
-    net.setsockopt(clientfd, SOL_SOCKET, SO_KEEPALIVE, 0)
-    loop.add(clientfd, (fd, event) => {
-      if (event & EPOLLERR || event & EPOLLHUP) {
-        return closeSocket(socket)
-      }
-      const bytes = net.recv(fd, buffer, buffer.offset, buffer.byteLength - buffer.offset)
-      if (bytes > 0) {
-        socket.onData(bytes)
-        return
-      }
-      if (bytes < 0) {
-        const errno = sys.errno()
-        if (errno === net.EAGAIN) return
-        just.error(`recv error: ${sys.strerror(errno)} (${errno})`)
-      }
-      closeSocket(socket)
-    })
-    let flags = sys.fcntl(clientfd, sys.F_GETFL, 0)
-    flags |= O_NONBLOCK
-    sys.fcntl(clientfd, sys.F_SETFL, flags)
-    loop.update(clientfd, readableMask)
-    socket.write = (buf, len = buf.byteLength, off = 0) => {
-      const written = net.send(clientfd, buf, len, off)
-      if (written > 0) {
-        return written
-      }
-      if (written < 0) {
-        const errno = sys.errno()
-        if (errno === net.EAGAIN) return written
-        just.error(`write error (${clientfd}): ${sys.strerror(errno)} (${errno})`)
-      }
-      if (written === 0) {
-        just.error(`zero write ${clientfd}`)
-      }
-      return written
-    }
-    socket.writeString = str => net.sendString(clientfd, str)
-    socket.close = () => closeSocket(socket)
-    const buffer = server.onConnect(socket)
-    buffer.offset = 0
-  }
-
-  function listen (maxconn = SOMAXCONN) {
-    const r = net.listen(sockfd, maxconn)
-    if (r === 0) loop.add(sockfd, onConnect)
-    return r
-  }
-  server.listen = listen
-
-  const sockfd = net.socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)
-  net.setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 1)
-  net.setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, 1)
-  net.bind(sockfd, host, port)
-
-  return server
-}
-
-function createClient (address = '127.0.0.1', port = 3000) {
-  const sock = { address, port, connected: false }
-  let fd
-
-  function closeSocket () {
-    sock.onClose && sock.onClose(sock)
-    loop.remove(fd)
-    net.close(fd)
-  }
-
-  function handleRead (fd, event) {
-    const bytes = net.recv(fd, buffer, buffer.offset, buffer.byteLength - buffer.offset)
-    if (bytes > 0) {
-      sock.onData(bytes)
-      return
-    }
-    if (bytes < 0) {
-      const errno = sys.errno()
-      if (errno === net.EAGAIN) return
-      just.print(`recv error: ${sys.strerror(errno)} (${errno})`)
-    }
-    closeSocket(sock)
-  }
-
-  function handleError (fd, event) {
-    const errno = net.getsockopt(fd, SOL_SOCKET, SO_ERROR)
-    if (!sock.connected) {
-      sock.onConnect(new Error(`${errno} : ${just.sys.strerror(errno)}`))
-    }
-  }
-
-  function handleWrite (fd, event) {
-    if (!sock.connected) {
-      net.setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, 0)
-      net.setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, 0)
-      let flags = sys.fcntl(fd, sys.F_GETFL, 0)
-      flags |= O_NONBLOCK
-      sys.fcntl(fd, sys.F_SETFL, flags)
-      loop.update(fd, readableMask)
-      buffer = sock.onConnect(null, sock)
-      buffer.offset = 0
-      sock.connected = true
-    }
-  }
-
-  function onSocketEvent (fd, event) {
-    if (event & EPOLLERR || event & EPOLLHUP) {
-      handleError(fd, event)
-      closeSocket()
-      return
-    }
-    if (event & EPOLLIN) {
-      handleRead(fd, event)
-    }
-    if (event & EPOLLOUT) {
-      handleWrite(fd, event)
-    }
-  }
-
-  sock.write = (buf, len = buf.byteLength, off = 0) => {
-    const written = net.send(fd, buf, len, off)
-    if (written > 0) {
-      return written
-    }
-    if (written < 0) {
-      const errno = sys.errno()
-      if (errno === net.EAGAIN) return written
-      just.error(`write error (${fd}): ${sys.strerror(errno)} (${errno})`)
-    }
-    if (written === 0) {
-      just.error(`zero write ${fd}`)
-    }
-    return written
-  }
-  sock.writeString = str => net.sendString(fd, str)
-
-  sock.close = () => closeSocket(sock)
-
-  function connect () {
-    fd = net.socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)
-    loop.add(fd, onSocketEvent, readableWritableMask)
-    net.connect(fd, address, port)
-    sock.fd = fd
-    return sock
-  }
-
-  let buffer
-  sock.connect = connect
-  return sock
-}
-
-module.exports = { createServer, createClient }

+ 0 - 38
frameworks/JavaScript/just/spawn.js

@@ -1,38 +0,0 @@
-const { cwd, errno, strerror, spawn } = just.sys
-const path = cwd()
-const [...args] = just.args.slice(2)
-const { socketpair, AF_UNIX, SOCK_STREAM } = just.net
-function createPipe () {
-  const fds = []
-  const r = socketpair(AF_UNIX, SOCK_STREAM, fds)
-  if (r !== 0) throw new Error(`socketpair ${r} errno ${errno()} : ${strerror(errno())}`)
-  return fds
-}
-
-const cpus = parseInt(just.env().CPUS || just.sys.cpus, 10)
-const pids = []
-for (let i = 0; i < cpus; i++) {
-  const stdin = createPipe()
-  const stdout = createPipe()
-  const stderr = createPipe()
-  const pid = spawn('just', path, args, stdin[1], stdout[1], stderr[1])
-  pids.push(pid)
-}
-
-const { readStat } = require('lib/monitor.js')
-const last = { user: 0, system: 0 }
-just.setInterval(() => {
-  const stat = { user: 0, system: 0, rss: 0 }
-  for (const pid of pids) {
-    const { utime, stime, rssPages } = readStat(pid)
-    const rss = Math.floor((rssPages * just.sys.pageSize) / (1024 * 1024))
-    stat.rss += rss
-    stat.user += utime
-    stat.system += stime
-  }
-  const user = stat.user - last.user
-  const system = stat.system - last.system
-  last.user = stat.user
-  last.system = stat.system
-  just.print(`children ${pids.length} rss ${stat.rss} user ${user} system ${system} total ${user + system}`)
-}, 1000)

+ 71 - 421
frameworks/JavaScript/just/techempower.js

@@ -1,431 +1,81 @@
-const { connect, constants } = require('lib/connection.js')
-const { createServer } = require('lib/tcp.js')
-const { createParser } = require('lib/http.js')
-const { sjs, attr } = require('lib/stringify.js')
+const stringify = require('@stringify')
+const html = require('@html')
+const cache = require('@cache')
+const dns = require('@dns')
+const postgres = require('@pg')
+const http = require('@http')
+const socket = require('@socket')
 
 
-function compile (sock, query) {
-  return new Promise((resolve, reject) => {
-    const result = sock.compile(query, err => {
-      if (err) return reject(err)
-      resolve(result)
-    })
-  })
-}
+const util = require('util.js')
+const config = require('tfb.config.js')
 
 
-async function onPGAuth (sock) {
-  sock.getWorldById = await compile(sock, {
-    formats: [{ format: 1, oid: INT4OID }],
-    sql: 'select id, randomNumber from World where id = $1',
-    fields: [{ format: 1, oid: INT4OID }],
-    name: 's1',
-    portal: '',
-    maxRows: 0,
-    params: [1]
-  })
-  sock.allFortunes = await compile(sock, {
-    formats: [],
-    sql: 'select * from Fortune',
-    fields: [{ format: 1, oid: INT4OID }, { format: 0, oid: VARCHAROID }],
-    name: 's2',
-    portal: '',
-    maxRows: 0,
-    htmlEscape: true,
-    params: []
-  })
-  sock.updateWorldById = await compile(sock, {
-    formats: [{ format: 1, oid: INT4OID }],
-    sql: 'update World set randomNumber = $2 where id = $1',
-    fields: [],
-    name: 's3',
-    portal: '',
-    maxRows: 0,
-    params: [1, 1]
-  })
-  // TODO: we could actually build these on the fly for any number of updates
-  sock.updateWorldById20 = await compile(sock, {
-    formats: [{ format: 1, oid: INT4OID }],
-    sql: `update world set randomnumber = CASE id 
-when $1 then $2 
-when $3 then $4 
-when $5 then $6 
-when $7 then $8 
-when $9 then $10 
-when $11 then $12 
-when $13 then $14 
-when $15 then $16 
-when $17 then $18 
-when $19 then $20 
-when $21 then $22 
-when $23 then $24 
-when $25 then $26 
-when $27 then $28 
-when $29 then $30 
-when $31 then $32 
-when $33 then $34 
-when $35 then $36 
-when $37 then $38 
-when $39 then $40
-else randomnumber 
-end where id in ($1,$3,$5,$7,$9,$11,$13,$15,$17,$19,$21,$23,$25,$27,$29,$31,$33,$35,$37,$39)
-`,
-    fields: [],
-    name: 's4',
-    portal: '',
-    maxRows: 0,
-    params: Array(40).fill(0)
-  })
-  sock.updateWorldById15 = await compile(sock, {
-    formats: [{ format: 1, oid: INT4OID }],
-    sql: `update world set randomnumber = CASE id 
-when $1 then $2 
-when $3 then $4 
-when $5 then $6 
-when $7 then $8 
-when $9 then $10 
-when $11 then $12 
-when $13 then $14 
-when $15 then $16 
-when $17 then $18 
-when $19 then $20 
-when $21 then $22 
-when $23 then $24 
-when $25 then $26 
-when $27 then $28 
-when $29 then $30 
-else randomnumber 
-end where id in ($1,$3,$5,$7,$9,$11,$13,$15,$17,$19,$21,$23,$25,$27,$29)
-`,
-    fields: [],
-    name: 's5',
-    portal: '',
-    maxRows: 0,
-    params: Array(30).fill(0)
-  })
-  sock.updateWorldById10 = await compile(sock, {
-    formats: [{ format: 1, oid: INT4OID }],
-    sql: `update world set randomnumber = CASE id 
-when $1 then $2 
-when $3 then $4 
-when $5 then $6 
-when $7 then $8 
-when $9 then $10 
-when $11 then $12 
-when $13 then $14 
-when $15 then $16 
-when $17 then $18 
-when $19 then $20 
-else randomnumber 
-end where id in ($1,$3,$5,$7,$9,$11,$13,$15,$17,$19)
-`,
-    fields: [],
-    name: 's6',
-    portal: '',
-    maxRows: 0,
-    params: Array(20).fill(0)
-  })
-  sock.updateWorldById5 = await compile(sock, {
-    formats: [{ format: 1, oid: INT4OID }],
-    sql: `update world set randomnumber = CASE id 
-when $1 then $2 
-when $3 then $4 
-when $5 then $6 
-when $7 then $8 
-when $9 then $10 
-else randomnumber 
-end where id in ($1,$3,$5,$7,$9)
-`,
-    fields: [],
-    name: 's7',
-    portal: '',
-    maxRows: 0,
-    params: Array(10).fill(0)
-  })
-  sock.getCachedWorldById = await compile(sock, {
-    formats: [{ format: 1, oid: INT4OID }],
-    sql: 'select id, randomNumber from World where id = $1',
-    fields: [{ format: 1, oid: INT4OID }],
-    name: 's8',
-    portal: '',
-    maxRows: 0,
-    params: [1]
-  })
-  clients.push(sock)
-  if (clients.length === poolSize) onPGReady()
-}
+const { getIPAddress } = dns
+const { createSocket } = socket
+const { createServer, responses } = http
+const { SimpleCache } = cache
+const { sprayer, sortByMessage, spawn, getUpdateQuery, Clock } = util
+const { sjs, attr } = stringify
+const { 
+  db, fortunes, worlds, templates,
+  maxQuery, maxRows, message, json,
+  extra 
+} = config
 
 
-function onPGConnect (err, sock) {
-  if (err) {
-    just.error(err.stack)
-    just.setTimeout(() => connect(tfb, onPGConnect), 1000)
-    return
-  }
-  sock.onClose = () => {
-    // todo: remove from pool and reconnect?
-    just.error('pg.close')
-  }
-  sock.start(err => {
-    if (err) return just.error(err.stack)
-    sock.authenticate(err => {
-      if (err) return just.error(err.stack)
-      onPGAuth(sock).catch(err => just.error(err.stack))
-    })
-  })
-}
+async function main () {
+  const spray = sprayer(maxQuery)
+  const getRandom = () => Math.ceil(Math.random() * maxRows)
+  const getCount = (qs = { q: 1 }) => {
+    return Math.min(parseInt((qs.q) || 1, 10), maxQuery) || 1
+  }
+  const sJSON = sjs({ message: attr('string') })
+  const wJSON = sjs({ id: attr('number'), randomnumber: attr('number') })  
+  const clock = new Clock()
 
 
-const HEADER = '<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>'
-const FOOTER = '</table></body></html>'
-const S1 = '<tr><td>'
-const S2 = '</td><td>'
-const S3 = '</td></tr>'
-function getHTML (rows) {
-  let html = HEADER
-  for (const row of rows) {
-    html += (S1 + row[0] + S2 + row[1] + S3)
-  }
-  return html + FOOTER
-}
+  const sock = createSocket()
+  const ip = await getIPAddress(db.hostname)
+  await sock.connect(ip, db.port)
+  const pg = await postgres.createSocket(sock, db)
 
 
-function insertionSort (arr) {
-  const n = arr.length
-  for (let i = 1; i < n; i++) {
-    const c = arr[i]
-    let j = i - 1
-    while ((j > -1) && (c[1] < arr[j][1])) {
-      arr[j + 1] = arr[j]
-      j--
-    }
-    arr[j + 1] = c
-  }
-  return arr
-}
+  sock.noDelay = false
 
 
-const cache = {}
+  const getWorldById = await pg.compile(worlds)
+  const getFortunes = await pg.compile(fortunes)
+  const worldCache = new SimpleCache(id => getWorldById(id))
+  const template = html.load(templates.fortunes, templates.settings)
+  const getRandomWorld = () => getWorldById(getRandom())
+  const getCachedWorld = () => worldCache.get(getRandom())
 
 
-function onHTTPConnect (sock) {
-  const client = clients[sock.fd % clients.length]
-  const rbuf = new ArrayBuffer(4096)
-  const parser = createParser(rbuf)
-  const { getWorldById, updateWorldById, allFortunes, updateWorldById20, updateWorldById15, updateWorldById10, updateWorldById5, getCachedWorldById } = client
-  const message = { message: 'Hello, World!' }
-  const text = 'Hello, World!'
-  const extra = [0, 'Additional fortune added at request time.']
-  const updateQueries = {
-    5: updateWorldById5,
-    10: updateWorldById10,
-    15: updateWorldById15,
-    20: updateWorldById20
-  }
-  const results = []
-  let queries = 0
-  let updates = 0
-  function onUpdateMulti () {
-    const json = JSON.stringify(results)
-    sock.writeString(`${rJSON}${json.length}${END}${json}`)
-  }
-  function onUpdateSingle () {
-    updates++
-    if (results.length === updates) {
-      const json = JSON.stringify(results)
-      sock.writeString(`${rJSON}${json.length}${END}${json}`)
-    }
-  }
-  function onUpdates () {
-    const [id, randomNumber] = getWorldById.getRows()[0]
-    results.push({ id, randomNumber })
-    if (results.length === queries) {
-      const query = updateQueries[queries]
-      if (query) {
-        let i = 0
-        for (const row of results) {
-          row.randomNumber = Math.ceil(Math.random() * 10000)
-          query.params[i++] = row.id
-          query.params[i++] = row.randomNumber
-        }
-        query.call(onUpdateMulti)
-        return
-      }
-      updates = 0
-      for (const row of results) {
-        row.randomNumber = Math.ceil(Math.random() * 10000)
-        updateWorldById.params[0] = row.id
-        updateWorldById.params[1] = row.randomNumber
-        updateWorldById.append(onUpdateSingle)
-      }
-      updateWorldById.send()
-    }
-  }
-  function handleUpdates (qs) {
-    const [, val] = qs.split('=')
-    queries = Math.min(parseInt(val || 1, 10), 500) || 1
-    results.length = 0
-    for (let i = 1; i < queries; i++) {
-      getWorldById.params[0] = Math.ceil(Math.random() * 10000)
-      getWorldById.append(onUpdates, (i % 20 === 0))
-    }
-    getWorldById.params[0] = Math.ceil(Math.random() * 10000)
-    getWorldById.append(onUpdates)
-    getWorldById.send()
-  }
-  function onMulti () {
-    const [id, randomNumber] = getWorldById.getRows()[0]
-    results.push({ id, randomNumber })
-    if (results.length === queries) {
-      const json = JSON.stringify(results)
-      sock.writeString(`${rJSON}${json.length}${END}${json}`)
-      queries = 0
-    }
-  }
-  function handleMulti (qs) {
-    const [, val] = qs.split('=')
-    queries = Math.min(parseInt(val || 1, 10), 500) || 1
-    results.length = 0
-    for (let i = 1; i < queries; i++) {
-      getWorldById.params[0] = Math.ceil(Math.random() * 10000)
-      getWorldById.append(onMulti, (i % 20 === 0))
-    }
-    getWorldById.params[0] = Math.ceil(Math.random() * 10000)
-    getWorldById.append(onMulti)
-    getWorldById.send()
-  }
-  function onCached () {
-    const row = getCachedWorldById.getRows()[0]
-    const [id, randomNumber] = row
-    const world = { id, randomNumber }
-    cache[id] = world
-    results.push(world)
-    if (results.length === queries) {
-      const json = JSON.stringify(results)
-      sock.writeString(`${rJSON}${json.length}${END}${json}`)
-      queries = 0
-      results.length = 0
-    }
-  }
-  function handleCached (qs) {
-    const [, val] = qs.split('=')
-    queries = Math.min(parseInt(val || 1, 10), 500) || 1
-    for (let i = 1; i < queries; i++) {
-      const id = Math.ceil(Math.random() * 10000)
-      const row = cache[id]
-      if (row) {
-        results.push(row)
-      } else {
-        getCachedWorldById.params[0] = id
-        getCachedWorldById.append(onCached, (i % 20 === 0))
-      }
-    }
-    const id = Math.ceil(Math.random() * 10000)
-    const row = cache[id]
-    if (row) {
-      results.push(row)
-    } else {
-      getCachedWorldById.params[0] = id
-      getCachedWorldById.append(onCached)
-    }
-    if (results.length === queries) {
-      const json = JSON.stringify(results)
-      sock.writeString(`${rJSON}${json.length}${END}${json}`)
-      queries = 0
-      results.length = 0
-      return
-    }
-    getCachedWorldById.send()
-  }
-  function onFortunes () {
-    const html = getHTML(insertionSort([extra, ...allFortunes.getRows()]))
-    sock.writeString(`${rHTML}${utf8Length(html)}${END}${html}`)
-  }
-  function onSingle () {
-    const [id, randomNumber] = getWorldById.getRows()[0]
-    const json = sDB({ id, randomNumber })
-    sock.writeString(`${rJSON}${json.length}${END}${json}`)
-  }
-  const queryPath = '/query'
-  const updatePath = '/update'
-  const cachePath = '/cached-world'
-  const pathSep = '?'
-  const END = '\r\n\r\n'
-  const handlers = {
-    '/json': () => {
-      const json = sJSON(message)
-      sock.writeString(`${rJSON}${json.length}${END}${json}`)
-    },
-    '/fortunes': () => allFortunes.call(onFortunes),
-    '/db': () => {
-      getWorldById.params[0] = Math.ceil(Math.random() * 10000)
-      getWorldById.call(onSingle)
-    },
-    '/plaintext': () => sock.writeString(`${rTEXT}${text.length}${END}${text}`),
-    default: url => {
-      const [path, qs] = url.split(pathSep)
-      if (path === queryPath) {
-        handleMulti(qs)
-        return
-      }
-      if (path === updatePath) {
-        handleUpdates(qs)
-        return
-      }
-      if (path === cachePath) {
-        handleCached(qs)
-        return
-      }
-      sock.writeString(r404)
-    }
-  }
-  parser.onRequests = count => {
-    if (count > 1) {
-      sock.writeString(`${rTEXT}${text.length}${END}${text}`.repeat(count))
-      return
-    }
-    const url = parser.url(0)
-    const handler = (handlers[url] || handlers.default)
-    handler(url)
-  }
-  sock.onData = bytes => parser.parse(bytes)
-  sock.onClose = () => {
-    parser.free()
-  }
-  return parser.buffer
-}
-
-function onPGReady () {
-  microtasks = false
-  just.print(`listen: ${server.listen()}`)
-}
+  const server = createServer()
+    .get('/plaintext', res => res.text(message))
+    .get('/json', res => res.utf8(sJSON(json), responses.json))
+    .get('/db', async res => {
+      res.utf8(wJSON(await getRandomWorld()), responses.json)
+    })
+    .get('/fortunes', async res => {
+      res.html(template.call(sortByMessage([extra, ...await getFortunes()])))
+    })
+    .get('/cached-world', async (res, req) => {
+      res.json(await Promise.all(spray(getCount(req.query), getCachedWorld)))
+    })
+    .get('/query', async (res, req) => {
+      res.json(await Promise.all(spray(getCount(req.query), getRandomWorld)))
+    })
+    .get('/update', async (res, req) => {
+      const count = getCount(req.query)
+      const worlds = await Promise.all(spray(count, getRandomWorld))
+      const updateWorlds = await getUpdateQuery(count, pg)
+      await updateWorlds(...worlds.map(w => {
+        w.randomnumber = getRandom()
+        return [w.id, w.randomnumber]
+      }).flat())
+      res.json(worlds)
+    })
+    .listen('0.0.0.0', 8080)
 
 
-const { utf8Length } = just.sys
-const poolSize = parseInt(just.env().PGPOOL || just.sys.cpus, 10)
-const server = createServer('0.0.0.0', 8080)
-server.onConnect = onHTTPConnect
-const { INT4OID, VARCHAROID } = constants.fieldTypes
-const clients = []
-const tfb = {
-  hostname: 'tfb-database',
-  port: 5432,
-  user: 'benchmarkdbuser',
-  pass: 'benchmarkdbpass',
-  database: 'hello_world'
+  clock.set(() => {
+    worldCache.tick()
+    server.update()
+  })
 }
 }
-let i = poolSize
-const sJSON = sjs({ message: attr('string') })
-const sDB = sjs({ id: attr('number'), randomNumber: attr('number') })
-while (i--) connect(tfb, onPGConnect)
-const { loop } = just.factory
-let microtasks = true
 
 
-let time = (new Date()).toUTCString()
-let rHTML = `HTTP/1.1 200 OK\r\nServer: j\r\nDate: ${time}\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: `
-let rTEXT = `HTTP/1.1 200 OK\r\nServer: j\r\nDate: ${time}\r\nContent-Type: text/plain\r\nContent-Length: `
-let rJSON = `HTTP/1.1 200 OK\r\nServer: j\r\nDate: ${time}\r\nContent-Type: application/json\r\nContent-Length: `
-let r404 = `HTTP/1.1 404 Not Found\r\nServer: j\r\nDate: ${time}\r\nContent-Type: text/plain\r\nContent-Length: 0\r\n\r\n`
-just.setInterval(() => {
-  time = (new Date()).toUTCString()
-  rHTML = `HTTP/1.1 200 OK\r\nServer: j\r\nDate: ${time}\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: `
-  rTEXT = `HTTP/1.1 200 OK\r\nServer: j\r\nDate: ${time}\r\nContent-Type: text/plain\r\nContent-Length: `
-  rJSON = `HTTP/1.1 200 OK\r\nServer: j\r\nDate: ${time}\r\nContent-Type: application/json\r\nContent-Length: `
-  r404 = `HTTP/1.1 404 Not Found\r\nServer: j\r\nDate: ${time}\r\nContent-Type: text/plain\r\nContent-Length: 0\r\n\r\n`
-}, 100)
-while (1) {
-  if (loop.poll(0) === 0) loop.poll(-1)
-  if (microtasks) just.sys.runMicroTasks()
-}
+spawn(main).catch(err => just.error(err.stack))

+ 56 - 0
frameworks/JavaScript/just/tfb.config.js

@@ -0,0 +1,56 @@
+const postgres = require('@pg')
+
+const { constants } = postgres
+const { BinaryInt, VarChar } = constants
+
+const db = {
+  hostname: 'tfb-database',
+  user: 'benchmarkdbuser',
+  pass: 'benchmarkdbpass',
+  database: 'hello_world',
+  version: constants.PG_VERSION,
+  port: 5432
+}
+
+const fortunes = {
+  portal: '',
+  formats: [],
+  name: 'fortunes',
+  maxRows: 0,
+  params: [],
+  sql: 'select * from Fortune',
+  fields: [
+    { format: BinaryInt, name: 'id' },
+    { format: VarChar, name: 'message', htmlEscape: true }
+  ]
+}
+
+const worlds = {
+  portal: '',
+  formats: [BinaryInt],
+  name: 'worlds',
+  maxRows: 0,
+  params: [0],
+  sql: 'select id, randomNumber from World where id = $1',
+  fields: [
+    { format: BinaryInt, name: 'id' },
+    { format: BinaryInt, name: 'randomnumber' }
+  ]
+}
+
+const templates = {
+  fortunes: 'fortunes.html',
+  settings: { rawStrings: false, compile: true }
+}
+
+const maxQuery = 500
+const maxRows = 10000
+const message = 'Hello, World!'
+const json = { message }
+const extra = { id: 0, message: 'Additional fortune added at request time.' }
+
+module.exports = {
+  db, fortunes, worlds, templates,
+  maxQuery, maxRows, message, json,
+  extra 
+}

+ 139 - 0
frameworks/JavaScript/just/util.js

@@ -0,0 +1,139 @@
+const process = require('process')
+const postgres = require('@pg')
+
+const { constants } = postgres
+const { BinaryInt } = constants
+
+/**
+ * Generate a Bulk Update SQL statement definition For a given table, identity 
+ * column and column to be updated, it will generate a single SQL
+ * statement to update all fields in one statement
+ *
+ * @param {string} table   - The name of the table
+ * @param {string} field   - The name of the field we want to update
+ * @param {string} id      - The name of the id field
+ * @param {string} updates - The number of rows to update in the statement
+ * @param {string} type    - The name of the table
+ */
+function generateBulkUpdate (table, field, id, updates = 5, formats = [BinaryInt]) {
+  function getIds (count) {
+    const updates = []
+    for (let i = 1; i < (count * 2); i += 2) {
+      updates.push(`$${i}`)
+    }
+    return updates.join(',')
+  }
+  function getClauses (count) {
+    const clauses = []
+    for (let i = 1; i < (count * 2); i += 2) {
+      clauses.push(`when $${i} then $${i + 1}`)
+    }
+    return clauses.join('\n')
+  }
+  const sql = []
+  sql.push(`update ${table} set ${field} = CASE ${id}`)
+  sql.push(getClauses(updates))
+  sql.push(`else ${field}`)
+  sql.push(`end where ${id} in (${getIds(updates)})`)
+  return {
+    formats,
+    fields: [],
+    name: `bulk.${updates}`,
+    portal: '',
+    params: Array(updates * 2).fill(0),
+    sql: sql.join('\n'),
+    sync: true
+  }
+}
+
+/**
+ * Utility function to generate an array of N values populated with provided
+ * map function. There seems to be no simpler/quicker way to do this in JS.
+ * @param {string} n     - Size of the array to create
+ * @param {string} field - The map function which will create each array value
+ */
+function sprayer (max = 100) {
+  const ar = [0]
+  for (let i = 0; i < max; i++) {
+    ar[i + 1] = (new Array(i + 1)).fill(1)
+  }
+  max += 1
+  return (n, fn) => ar[n % max].map(fn)
+}
+
+function sortByMessage (arr) {
+  const n = arr.length
+  for (let i = 1; i < n; i++) {
+    const c = arr[i]
+    let j = i - 1
+    while ((j > -1) && (c.message < arr[j].message)) {
+      arr[j + 1] = arr[j]
+      j--
+    }
+    arr[j + 1] = c
+  }
+  return arr
+}
+
+function spawn (main) {
+  if (just.env()['WORKER']) return main()
+  const { watch, launch } = process
+  const processes = []
+  const cpus = parseInt(just.env().CPUS || just.sys.cpus, 10)
+  for (let i = 0; i < cpus; i++) {
+    just.sys.setenv('WORKER', i)
+    //const proc = launch(just.args[0], ['--trace-gc', ...just.args.slice(1)])
+    const proc = launch(just.args[0], just.args.slice(1))
+    processes.push(proc)
+    proc.stats = { user: 0, system: 0 }
+  }
+  return Promise.all(processes.map(p => watch(p)))
+}
+
+const updates = new Map()
+
+function getUpdateQuery (count, pg, formats = [BinaryInt]) {
+  const query = updates.get(count)
+  if (query) return query
+  const promise = pg.compile(generateBulkUpdate('world', 'randomnumber', 'id', count, formats))
+  updates.set(count, promise)
+  return promise
+}
+
+class Clock {
+  constructor () {
+    this.slots = new Map()
+  }
+
+  unset (callback, repeat = 1000) {
+    const current = this.slots.get(repeat)
+    if (!current) return
+    current.callbacks = current.callbacks.filter(cb => cb !== callback)
+    if (!current.callbacks.length) {
+      just.clearTimeout(current.timer)
+      this.slots.delete(repeat)
+    }
+  }
+
+  set (callback, repeat = 1000) {
+    let current = this.slots.get(repeat)
+    if (current) {
+      current.callbacks.push(callback)
+      return
+    }
+    current = {
+      callbacks: [callback],
+      timer: just.setInterval(() => current.callbacks.forEach(cb => cb()), repeat)
+    }
+    this.slots.set(repeat, current)
+  }
+}
+
+module.exports = {
+  sprayer,
+  spawn,
+  sortByMessage,
+  generateBulkUpdate,
+  getUpdateQuery,
+  Clock
+}