[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  test:\n    name: Test on node ${{ matrix.node }} and ${{ matrix.os }}\n\n    runs-on: ${{ matrix.os }}\n\n    strategy:\n      matrix:\n        node: [18]\n        os: [ubuntu-latest]\n\n    steps:\n      - uses: actions/checkout@v4\n      - name: Use node ${{ matrix.node }}\n        uses: actions/setup-node@v3\n        with:\n          node-version: ${{ matrix.node }}\n      - name: Build\n        run: npm install\n      - name: Test\n        run: npm test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules\njspm_packages\n\n# Optional npm cache directory\n.npm\n\n# Optional REPL history\n.node_repl_history\n\n\npublic/vs\n\n# Visual Studio files\n.vs/\nvisual/\nbin\nobj\n*.sln\n*.njsproj\n\n"
  },
  {
    "path": "LICENSE",
    "content": "BSD 2-Clause License\n\nCopyright (c) 2017, Fred Tingaud\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# quick-bench-back-end\nBack end side of quick-bench\n"
  },
  {
    "path": "about-container",
    "content": "#!/bin/bash\n\ndocker run --rm -t fredtingaud/quick-bench:\"$1\" /bin/bash -c ./about-me\n"
  },
  {
    "path": "app-build.js",
    "content": "#!/usr/bin/env node\n\nimport express from 'express';\nimport cors from 'cors';\nimport path from 'path';\nimport url from 'url';\nconst __dirname = path.dirname(url.fileURLToPath(import.meta.url));\nconst app = express();\napp.use(express.static(path.join(__dirname, 'quick-bench-front-end', 'build-bench', 'build')));\nimport bodyParser from 'body-parser';\nimport multer from 'multer';\nimport * as libbuild from './src/libbuild.js';\nimport * as docker from './src/docker.js';\n\nconst PORT = process.env.BB_PORT | 4000;\n\nconst upload = multer();\n\napp.use(bodyParser.json());\napp.use(cors());\n\nlibbuild.updateAvailableContainersList();\n\napp.get('/build-env', upload.array(), function (req, res) {\n    res.json(libbuild.getEnv());\n});\n\napp.post('/build', upload.array(), function (req, res) {\n    Promise.resolve(libbuild.benchmark(req.body, req.headers))\n        .then((done) => res.json(libbuild.makeBuildGraphResult(done)))\n        .catch((err) => res.json({ messages: [err] }));\n});\n\napp.get('/build/:id', upload.array(), function (req, res) {\n    console.log('Get ' + req.params.id + ' ' + JSON.stringify(req.headers));\n    Promise.resolve(libbuild.reload(req.params.id))\n        .then((done) => res.json(libbuild.getRequestAndResult(done)))\n        .catch(() => res.json({ messages: [`Could not load ${req.params.id}`] }));\n});\n\napp.get('/containers/', upload.array(), function (req, res) {\n    if (process.env.ALLOW_CONTAINER_DOWNLOAD) {\n        Promise.resolve(docker.getTags()).then(t => res.json({ \"tags\": t }));\n    } else {\n        res.status(403).send({\n            message: 'Access Forbidden'\n        });\n    }\n});\n\napp.post('/containers/', upload.array(), function (req, res) {\n    if (process.env.ALLOW_CONTAINER_DOWNLOAD) {\n        Promise.resolve(docker.loadContainers(req.body.tags))\n            .then(() => libbuild.updateAvailableContainersList())\n            .then(() => res.json(libbuild.getEnv()))\n            .catch(e => res.status(500).send('Could not load containers'));\n    } else {\n        res.status(403).send({\n            message: 'Access Forbidden'\n        });\n    }\n});\n\napp.delete('/containers/', upload.array(), function (req, res) {\n    if (process.env.ALLOW_CONTAINER_DOWNLOAD) {\n        Promise.resolve(docker.deleteContainers(req.body.tags))\n            .then(() => libbuild.updateAvailableContainersList())\n            .then(() => res.json(libbuild.getEnv()))\n            .catch(e => res.status(500).send('Could not delete containers'));\n    } else {\n        res.status(403).send({\n            message: 'Access Forbidden'\n        });\n    }\n});\n\napp.get('/:id', upload.array(), function (req, res) {\n    res.redirect(`/b/${req.params.id}`);\n});\n\napp.get('/b/:id', upload.array(), function (req, res) {\n    res.sendFile(path.join(__dirname, 'quick-bench-front-end', 'build-bench', 'build', 'index.html'));\n});\n\napp.listen(PORT, function () {\n    console.log(`Listening to commands on port ${PORT}`);\n});\n"
  },
  {
    "path": "app-quick.js",
    "content": "#!/usr/bin/env node\n\nimport express from 'express';\nimport cors from 'cors';\nimport path from 'path';\nimport url from 'url';\nconst __dirname = path.dirname(url.fileURLToPath(import.meta.url));\nconst app = express();\napp.use(express.static(path.join(__dirname, 'quick-bench-front-end', 'quick-bench', 'build')));\nimport bodyParser from 'body-parser';\nimport multer from 'multer';\nimport * as libquick from './src/libquick.js';\nimport * as docker from './src/docker.js';\n\nconst PORT = process.env.QB_PORT | 4000;\nconst POST_LIMIT = process.env.QB_POST_LIMIT | (100 * 1024);\n\nconst upload = multer();\n\napp.use(bodyParser.json({limit: POST_LIMIT}));\napp.use(bodyParser.urlencoded({ limit: POST_LIMIT, extended: true }));\napp.use(cors());\n\nlibquick.updateAvailableContainersList();\n\napp.get('/quick-env', upload.array(), function (req, res) {\n    res.json(libquick.getEnv());\n});\n\napp.post('/quick', upload.array(), function (req, res) {\n    Promise.resolve(libquick.benchmark(req.body, req.headers))\n        .then((done) => res.json(libquick.makeGraphResult(done.res ? JSON.parse(done.res) : null, done.stdout, done.id, done.annotation, done.disassemblyOption)))\n        .catch((err) => res.json({ message: err }));\n});\n\napp.get('/quick/:id', upload.array(), function (req, res) {\n    console.log('Get ' + req.params.id + ' ' + JSON.stringify(req.headers));\n    Promise.resolve(libquick.reload(req.params.id))\n        .then((done) => res.json(libquick.getRequestAndResult(done)))\n        .catch(() => res.json({ message: 'Could not load given id' }));\n});\n\napp.get('/containers/', upload.array(), function (req, res) {\n    if (process.env.ALLOW_CONTAINER_DOWNLOAD) {\n        Promise.resolve(docker.getTags()).then(t => res.json({ \"tags\": t }));\n    } else {\n        res.status(403).send({\n            message: 'Access Forbidden'\n        });\n    }\n});\n\napp.post('/containers/', upload.array(), function (req, res) {\n    if (process.env.ALLOW_CONTAINER_DOWNLOAD) {\n        Promise.resolve(docker.loadContainers(req.body.tags))\n            .then(() => libquick.updateAvailableContainersList())\n            .then(() => res.json(libquick.getEnv()))\n            .catch(e => res.status(500).send('Could not load containers'));\n    } else {\n        res.status(403).send({\n            message: 'Access Forbidden'\n        });\n    }\n});\n\napp.delete('/containers/', upload.array(), function (req, res) {\n    if (process.env.ALLOW_CONTAINER_DOWNLOAD) {\n        Promise.resolve(docker.deleteContainers(req.body.tags))\n            .then(() => libquick.updateAvailableContainersList())\n            .then(() => res.json(libquick.getEnv()))\n            .catch(e => res.status(500).send('Could not delete containers'));\n    } else {\n        res.status(403).send({\n            message: 'Access Forbidden'\n        });\n    }\n});\n\napp.get('/q/:id', upload.array(), function (req, res) {\n    res.sendFile(path.join(__dirname, 'quick-bench-front-end', 'quick-bench', 'build', 'index.html'));\n});\n\napp.get('/:id', upload.array(), function (req, res) {\n    res.redirect(`/q/${req.params.id}`);\n});\n\napp.listen(PORT, function () {\n    console.log(`Listening to commands on port ${PORT}`);\n});\n"
  },
  {
    "path": "deploy",
    "content": "#!/bin/bash\n\nsudo yum update -y\nsudo yum install -y docker procmail\nsudo curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -\nsudo yum install -y nodejs\ncd /srv/quick-bench-back-end/\nsudo service docker start\nsudo useradd -M -s /sbin/nologin -r -G docker quick-bench\nmkdir -m 777 -p $(printf \"/data/%02x \" $(seq 0 255))\nsudo ./pull-docker\nsudo cp quick-benchd /etc/init.d/.\nsudo npm install\nsudo ./seccomp.js\nsudo sysctl -w kernel.perf_event_paranoid=1\nsudo service quick-benchd start\n"
  },
  {
    "path": "kill-docker",
    "content": "#!/bin/bash\n\nFILE=$1.cid\nCONTAINERFILE=$1.cont\n\nif [ -f \"$FILE\" ]; then\n    docker kill \"$(cat \"$FILE\")\"\n    rm \"$1\".out\n    rm \"$1\".build\n    rm -f \"$1\".perf\n    rm \"$FILE\"\n    docker rm -f \"$(cat \"$CONTAINERFILE\")\"\nfi\nrm -f \"$1\".lock\n"
  },
  {
    "path": "list-containers",
    "content": "#!/bin/bash\n\ndocker images fredtingaud/quick-bench --format \"{{.Tag}}\"\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"quick-bench-server\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Server side of Quick-Bench\",\n  \"main\": \"index.js\",\n  \"directories\": {\n    \"test\": \"test\"\n  },\n  \"scripts\": {\n    \"test\": \"mocha --exit\",\n    \"system-test\": \"mocha system-test --exit\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"gitolite3@ns377538.ip-91-121-210.eu:quick-bench-server\"\n  },\n  \"keywords\": [\n    \"C++\",\n    \"benchmark\"\n  ],\n  \"author\": \"Fred Tingaud\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"body-parser\": \"^1.20.2\",\n    \"child_process\": \"^1.0.2\",\n    \"cors\": \"^2.8.5\",\n    \"express\": \"^4.18.2\",\n    \"multer\": \"^1.4.5-lts.1\",\n    \"node-fetch\": \"^3.3.2\",\n    \"sha1\": \"^1.1.1\"\n  },\n  \"devDependencies\": {\n    \"chai\": \"^4.3.8\",\n    \"mocha\": \"^10.2.0\"\n  },\n  \"type\": \"module\"\n}\n"
  },
  {
    "path": "pull-docker",
    "content": "#!/bin/bash\n\ndocker pull -a fredtingaud/quick-bench\n"
  },
  {
    "path": "quick-benchd",
    "content": "#!/bin/sh\n### BEGIN INIT INFO\n# Provides:\n# Required-Start:    $remote_fs $syslog\n# Required-Stop:     $remote_fs $syslog\n# Default-Start:     2 3 4 5\n# Default-Stop:      0 1 6\n# Short-Description: Start daemon at boot time\n# Description:       Enable service provided by daemon.\n### END INIT INFO\n\ndir=\"/srv/quick-bench-back-end\"\ncmd=\"NODE_ENV=production ./app.js\"\nuser=\"quick-bench\"\n\nname=$(basename \"$0\")\npid_file=\"/var/run/$name.pid\"\nstdout_log=\"/var/log/$name.log\"\nstderr_log=\"/var/log/$name.err\"\n\nget_pid() {\n    cat \"$pid_file\"\n}\n\nis_running() {\n    [ -f \"$pid_file\" ] && ps \"$(get_pid)\" > /dev/null 2>&1\n}\n\ncase \"$1\" in\n    start)\n    if is_running; then\n        echo \"Already started\"\n    else\n        echo \"Starting $name\"\n        cd \"$dir\"\n        if [ -z \"$user\" ]; then\n            sudo \"$cmd\" >> \"$stdout_log\" 2>> \"$stderr_log\" &\n        else\n            sudo -u \"$user\" \"$cmd\" >> \"$stdout_log\" 2>> \"$stderr_log\" &\n        fi\n        echo $! > \"$pid_file\"\n        if ! is_running; then\n            echo \"Unable to start, see $stdout_log and $stderr_log\"\n            exit 1\n        fi\n    fi\n    ;;\n    stop)\n    if is_running; then\n        echo -n \"Stopping $name..\"\n        kill \"$(get_pid)\"\n        for i in {1..10}\n        do\n            if ! is_running; then\n                break\n            fi\n\n            echo -n \".\"\n            sleep 1\n        done\n        echo\n\n        if is_running; then\n            echo \"Not stopped; may still be shutting down or shutdown may have failed\"\n            exit 1\n        else\n            echo \"Stopped\"\n            if [ -f \"$pid_file\" ]; then\n                rm \"$pid_file\"\n            fi\n        fi\n    else\n        echo \"Not running\"\n    fi\n    ;;\n    restart)\n    $0 stop\n    if is_running; then\n        echo \"Unable to stop, will not attempt to start\"\n        exit 1\n    fi\n    $0 start\n    ;;\n    status)\n    if is_running; then\n        echo \"Running\"\n    else\n        echo \"Stopped\"\n        exit 1\n    fi\n    ;;\n    *)\n    echo \"Usage: $0 {start|stop|restart|status}\"\n    exit 1\n    ;;\nesac\n\nexit 0\n"
  },
  {
    "path": "run-docker",
    "content": "#!/bin/bash\n\nset -e\n\nLOCAL_FILE=$(realpath \"$1\")\n\nCOMPILER=$2\nOPTIM_FLAG=$3\nVERSION_FLAG=$4\nASM_FORMAT=$5\nCLEAN_CACHE=$6\nLIB_VERSION=$7\nADDITIONAL_FLAGS=${*:8}\n\nif ! [[ $COMPILER == \"clang-\"?*\".\"? || $COMPILER == \"gcc-\"?*\".\"? ]] ; then\n    >&2 echo \"Unknown compiler\"\n    exit 1\nfi\n\nif [ \"$OPTIM_FLAG\" == 0 ]; then\n    OPTIM=\"\"\nelif [ \"$OPTIM_FLAG\" == 1 ]; then\n    OPTIM=\"-O1\"\nelif [ \"$OPTIM_FLAG\" == 2 ]; then\n    OPTIM=\"-O2\"\nelif [ \"$OPTIM_FLAG\" == 3 ]; then\n    OPTIM=\"-O3\"\nelif [ \"$OPTIM_FLAG\" == \"S\" ]; then\n    OPTIM=\"-Os\"\nelif [ \"$OPTIM_FLAG\" == \"G\" ]; then\n    OPTIM=\"-Og\"\nelif [ \"$OPTIM_FLAG\" == \"F\" ]; then\n    OPTIM=\"-Ofast\"\nelse\n    >&2 echo \"Unsupported optimization flag ${OPTIM_FLAG}\"\n    exit 1\nfi\n\nif [[ $VERSION_FLAG =~ c\\+\\+[0-9][0-9a-z] ]]; then\n    VERSION=\"-std=${VERSION_FLAG}\"\nelse\n    >&2 echo \"Unknown STD version\"\n    exit 1\nfi\n\nif [[ $ADDITIONAL_FLAGS =~ \\B(?!\\-f) ]]; then\n    >&2 echo \"Unsupported flag\"\n    exit 1\nfi\n\nif [[ $ASM_FORMAT =~ ^(?!(no|att|intel).)*$ ]]; then\n    >&2 echo \"Unsupported ASM format\"\n    exit 1\nfi\n\nLOCK=$LOCAL_FILE.lock\nlockfile \"$LOCK\"\nINFILE=$LOCAL_FILE.cpp\nOUTFILE=$LOCAL_FILE.out\nCIDFILE=$LOCAL_FILE.cid\nPERFFILE=$LOCAL_FILE.perf\nFUNCFILE=$LOCAL_FILE.func\nCONTAINERFILE=$LOCAL_FILE.cont\n\nif [ \"$CLEAN_CACHE\" = true ] && [ -f \"$OUTFILE\" ]; then\n    rm \"$OUTFILE\"\n    rm -f \"$PERFFILE\"\nfi\nif [ -f \"$OUTFILE\" ] && [[ \"$RECORD_PERF\" = false || -f \"$PERFFILE\" ]]; then\n    >&2 echo \"Showing cached results\"\nelse\n    touch \"$OUTFILE\"\n    chmod 666 \"$OUTFILE\"\n\n    if [ -z \"$UNLIMITED_RESOURCES\" ]; then\n        MEMORY_LIMITS='--memory=500m --cpu-period=100000 --cpu-quota=25000'\n    fi\n\n    if [ \"${ASM_FORMAT}\" != \"no\" ]; then\n        touch \"$PERFFILE\"\n        chmod 666 \"$PERFFILE\"\n        ANNOTATE=\"--security-opt seccomp=seccomp.json\"\n        ANNOTATE_CMD=\" && ./annotate -M${ASM_FORMAT}\"\n        ANNOTATE_RECORD=\"perf record -g\"\n        ANNOTATE_IN=\"docker cp $FUNCFILE \\$CONTAINER:/home/builder/bench.func\"\n        ANNOTATE_OUT=\"docker cp \\$CONTAINER:/home/builder/bench.perf $PERFFILE\"\n    fi\n    if [[ $LIB_VERSION == llvm ]] && [[ $COMPILER == clang* ]]; then\n        BUILD_COMMAND=build-libcxx\n    else\n        BUILD_COMMAND=build\n    fi\n    CONTAINER=$(docker create $ANNOTATE $MEMORY_LIMITS --cidfile=\"$CIDFILE\" -t fredtingaud/quick-bench:\"$COMPILER\" /bin/bash -c \"./$BUILD_COMMAND $OPTIM $VERSION $ADDITIONAL_FLAGS && $ANNOTATE_RECORD ./run $ANNOTATE_CMD\")\n    echo \"$CONTAINER\" > \"$CONTAINERFILE\"\n    docker cp \"$INFILE\" \"$CONTAINER\":/home/builder/bench-file.cpp\n    eval $ANNOTATE_IN\n    docker start -a \"$CONTAINER\"\n    docker cp \"$CONTAINER\":/home/builder/bench.out \"$OUTFILE\"\n    eval $ANNOTATE_OUT\n    docker rm \"$CONTAINER\"\n    rm \"$CONTAINERFILE\"\n    rm \"$CIDFILE\"\nfi\n\nrm -f \"$LOCK\"\n"
  },
  {
    "path": "run-docker-builder",
    "content": "#!/bin/bash\n\nset -e\n\nLOCAL_FILE=$(realpath \"$1\")\n\nCOMPILER=$2\nOPTIM_FLAG=$3\nVERSION_FLAG=$4\nCLEAN_CACHE=$6\nLIB_VERSION=$7\nFILE_NAME=$8.cpp\nRECORD_ASM=$9\nRECORD_PP=${10}\nADDITIONAL_FLAGS=${*:11}\n\nif ! [[ $COMPILER == \"clang-\"?*\".\"? || $COMPILER == \"gcc-\"?*\".\"? ]] ; then\n    >&2 echo \"Unknown compiler\"\n    exit 1\nfi\n\nif [ \"$OPTIM_FLAG\" == 0 ]; then\n    OPTIM=\"\"\nelif [ \"$OPTIM_FLAG\" == 1 ]; then\n    OPTIM=\"-O1\"\nelif [ \"$OPTIM_FLAG\" == 2 ]; then\n    OPTIM=\"-O2\"\nelif [ \"$OPTIM_FLAG\" == 3 ]; then\n    OPTIM=\"-O3\"\nelif [ \"$OPTIM_FLAG\" == \"S\" ]; then\n    OPTIM=\"-Os\"\nelif [ \"$OPTIM_FLAG\" == \"G\" ]; then\n    OPTIM=\"-Og\"\nelif [ \"$OPTIM_FLAG\" == \"F\" ]; then\n    OPTIM=\"-Ofast\"\nelse\n    >&2 echo \"Unsupported optimization flag ${OPTIM_FLAG}\"\n    exit 1\nfi\n\nif [[ $VERSION_FLAG =~ c\\+\\+[0-9][0-9a-z] ]]; then\n    VERSION=\"-std=${VERSION_FLAG}\"\nelse\n    >&2 echo \"Unknown STD version\"\n    exit 1\nfi\n\nif [[ $ADDITIONAL_FLAGS =~ \\B(?!\\-f) ]]; then\n    >&2 echo \"Unsupported flag\"\n    exit 1\nfi\n\nLOCK=$LOCAL_FILE.lock\nlockfile \"$LOCK\"\nINFILE=$LOCAL_FILE.cpp\nOUTFILE=$LOCAL_FILE.build\nINCLUDES=$LOCAL_FILE.inc\nASM=$LOCAL_FILE.s\nPP=$LOCAL_FILE.i\nCIDFILE=$LOCAL_FILE.cid\nCONTAINERFILE=$LOCAL_FILE.cont\nif [ \"$CLEAN_CACHE\" = true ] && [ -f \"$OUTFILE\" ]; then\n    rm \"$OUTFILE\"\n    rm -f \"$INCLUDES\"\n    rm -f \"$ASM\"\n    rm -f \"$PP\"\nfi\nif [ -f \"$OUTFILE\" ]; then\n    >&2 echo \"Showing cached results\"\nelse\n    touch \"$OUTFILE\"\n    chmod 666 \"$OUTFILE\"\n    touch \"$INCLUDES\"\n    chmod 666 \"$INCLUDES\"\n    \n    if [ -z \"$UNLIMITED_RESOURCES\" ]; then\n        MEMORY_LIMITS='--memory=500m --cpu-period=100000 --cpu-quota=25000'\n    fi\n\n    if [[ $LIB_VERSION == llvm ]] && [[ $COMPILER == clang* ]]; then\n        BUILD_COMMAND=time-build-libcxx\n        PREBUILD_COMMAND=prebuild-libcxx\n    else\n        BUILD_COMMAND=time-build\n        PREBUILD_COMMAND=prebuild\n    fi\n\n    if [ \"$RECORD_PP\" = true ]; then\n        touch \"$PP\"\n        chmod 666 \"$PP\"\n\tPP_OUT=\"docker cp \\$CONTAINER:/home/builder/bench.i $PP\"\n    fi\n    if [ \"$RECORD_ASM\" != \"none\" ]; then\n        touch \"$ASM\"\n        chmod 666 \"$ASM\"\n\tASM_OUT=\"docker cp \\$CONTAINER:/home/builder/bench.s $ASM\"\n    fi\n\n    PREBUILD_PARAMS=\"$RECORD_PP $RECORD_ASM\"\n    if [ -z ${BB_TIMEOUT+x} ]; then\n        ENV_PARAMS=\"-e BB_TIMEOUT=$BB_TIMEOUT\"\n    fi\n    if [ -z ${BB_MAX_ITERATION+x} ]; then\n        ENV_PARAMS=\"$ENV_PARAMS -e BB_MAX=$BB_MAX_ITERATION\"\n    fi\n    CONTAINER=$(docker create $ANNOTATE $MEMORY_LIMITS \\\n                              --cidfile=\"$CIDFILE\" \\\n                              $ENV_PARAMS \\\n               fredtingaud/quick-bench:\"$COMPILER\" /bin/bash -c \"./$PREBUILD_COMMAND $FILE_NAME $PREBUILD_PARAMS $OPTIM $VERSION $ADDITIONAL_FLAGS && ./$BUILD_COMMAND $FILE_NAME $OPTIM $VERSION $ADDITIONAL_FLAGS\"\n    )\n    echo \"$CONTAINER\" > \"$CONTAINERFILE\"\n    docker cp \"$INFILE\" \"$CONTAINER\":/home/builder/\"$FILE_NAME\"\n    docker start -a \"$CONTAINER\"\n    docker cp \"$CONTAINER\":/home/builder/bench.out \"$OUTFILE\"\n    docker cp \"$CONTAINER\":/home/builder/bench.inc \"$INCLUDES\"\n    eval $PP_OUT\n    eval $ASM_OUT\n    docker rm \"$CONTAINER\"\n    rm \"$CONTAINERFILE\"\n    rm \"$CIDFILE\"\nfi\n\nrm -f \"$LOCK\"\n"
  },
  {
    "path": "seccomp.js",
    "content": "#!/usr/bin/env node\n\nimport fs from 'fs';\nimport https from 'https';\n\nconst req = https.request('https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json', function (res) {\n\tres.setEncoding('utf-8');\n\tlet body = '';\n\tres.on('data', function (chunk) {\n\t\tbody = body + chunk;\n\t});\n\n\tres.on('end', () => {\n\t\tlet source = JSON.parse(body);\n\t\tsource.syscalls[0].names.push('perf_event_open');\n\t\tfs.writeFileSync('seccomp.json', JSON.stringify(source, null, 2));\n\t});\n}).on('error', (e) => {\n\tconsole.error('Error while getting seccomp.js:\\n' + e);\n});\n\nreq.end();\n"
  },
  {
    "path": "src/docker.js",
    "content": "import { exec } from 'child_process';\nimport fetch from 'node-fetch';\n\nconst getToken = async () => {\n    const response = await fetch('https://auth.docker.io/token?service=registry.docker.io&scope=repository:fredtingaud/quick-bench:pull');\n    const auth = await response.json();\n    return auth['token'];\n};\n\nconst getTags = async () => {\n    const token = await getToken();\n    const response = await fetch('https://registry-1.docker.io/v2/fredtingaud/quick-bench/tags/list', {\n        method: \"GET\",\n        headers: {\n            \"Authorization\": `Bearer ${token}`,\n            \"Content-type\": \"application/json\",\n            \"Accept\": \"application/json\",\n            \"Accept-Charset\": \"utf-8\"\n        }\n    });\n    const json = await response.json();\n    return json['tags'].sort(sortContainers);\n};\n\n/*\n * We sort clang containers before gcc containers.\n * If both are from the same compiler, we want the highest version (numerically, not alphabetically) first.\n */\nfunction sortContainers(c1, c2) {\n    if (c1.startsWith('clang')) {\n        if (c2.startsWith('clang')) {\n            let v1 = Number.parseFloat(c1.substr('clang-'.length));\n            let v2 = Number.parseFloat(c2.substr('clang-'.length));\n            return v2 - v1;\n        } else {\n            return -1;\n        }\n    } else {\n        if (c2.startsWith('gcc')) {\n            let v1 = Number.parseFloat(c1.substr('gcc-'.length));\n            let v2 = Number.parseFloat(c2.substr('gcc-'.length));\n            return v2 - v1;\n        } else {\n            return 1;\n        }\n    }\n}\n\nfunction describeContainer(name) {\n    return new Promise((resolve, reject) => {\n        return exec('./about-container ' + name, {}, (err, stdout, stderr) => {\n            if (err) {\n                reject(`Couldn't describe container for ${name}:\\n${stderr}`);\n            } else {\n                let result = {name: name};\n                let title = '';\n                for (const l of stdout.split('\\n')) {\n                    const line = l.trim();\n                    if (line === \"\") {\n                        continue;\n                    }\n                    if (line.startsWith('[') && line.endsWith(']')){\n                        title = line.substring(1, line.length - 1);\n                        result[title] = [];\n                    } else {\n                        result[title].push(line)\n                    }\n                }\n                resolve(result);\n            };\n        });\n    });\n}\n\nfunction readContainersList(stdout) {\n    return stdout.split('\\n').filter(Boolean).sort(sortContainers);\n}\n\nfunction listContainers(target) {\n    return new Promise((resolve, reject) => {\n        return exec('./list-containers', {}, (err, stdout, stderr) => {\n            if (err) {\n                reject(stderr);\n            } else {\n                resolve(stdout);\n            }\n        });\n    }).then(stdout => {\n        return Promise.all(readContainersList(stdout).map(c => describeContainer(c)));\n    }).then(m => {\n        console.log(JSON.stringify(m));\n        target.push(...m);\n    }).catch(e => console.log(e));\n}\n\nfunction loadOneContainer(container) {\n    return new Promise((resolve, reject) => {\n        return exec('docker pull fredtingaud/quick-bench:' + container, {}, function (err, stdout, stderr) {\n            if (err) {\n                reject(stderr);\n            } else {\n                resolve();\n            }\n        });\n    });\n}\n\nfunction deleteOneContainer(container) {\n    return new Promise((resolve, reject) => {\n        return exec('docker rmi fredtingaud/quick-bench:' + container, {}, function (err, stdout, stderr) {\n            if (err) {\n                reject(stderr);\n            } else {\n                resolve();\n            }\n        });\n    });\n}\n\nasync function loadContainers(targetList) {\n    await Promise.all(targetList.map(t => loadOneContainer(t)));\n}\n\nasync function deleteContainers(targetList) {\n    await Promise.all(targetList.map(t => deleteOneContainer(t)));\n}\n\nexport { listContainers, readContainersList, getTags, loadContainers, deleteContainers };\n"
  },
  {
    "path": "src/libbuild.js",
    "content": "import { exec } from 'child_process';\nimport fs from 'fs';\nimport * as tools from './tools.js';\nimport sha1 from 'sha1';\nimport * as docker from './docker.js';\n\nvar AVAILABLE_CONTAINERS = [];\n\nconst MAX_CODE_LENGTH = process.env.BB_CODE_LIMIT || 20000;\nconst TIMEOUT = parseInt(process.env.BB_TIMEOUT, 10) < 0 ? 0 : (parseInt(process.env.BB_TIMEOUT, 10) + 10 || 70);\nconst ALLOW_CONTAINER_DOWNLOAD = process.env.ALLOW_CONTAINER_DOWNLOAD;\n\nconst WRITE_PATH = '/data';\n\nclass BenchError extends Error{\n    constructor(message) {\n        super(message);\n        this.name = \"BenchError\";\n    }\n}\n\nasync function listContainers() {\n    AVAILABLE_CONTAINERS = [];\n    await docker.listContainers(AVAILABLE_CONTAINERS);\n}\n\nfunction cleanFilename(text) {\n    if (text === '')\n        return '_';\n    return text.replace(/[^\\w-]/gi, '_');\n}\n\nfunction runDockerCommand(fileName, request, force) {\n    return `./run-docker-builder ${fileName} ${request.compiler} ${request.optim} ${request.cppVersion} ${(request.isAnnotated || false)} ${(force || false)} ${(request.lib || 'gnu')} ${cleanFilename(request.title)} ${(request.asm || 'none')} ${(request.withPP || false)} ${request.flags.join(' ')}`;\n}\n\nfunction optionsToString(request, protocolVersion) {\n    let options = {\n        \"protocolVersion\": protocolVersion,\n        \"compiler\": request.compiler,\n        \"optim\": request.optim,\n        \"cppVersion\": request.cppVersion,\n        \"lib\": request.lib,\n        \"asm\": request.asm,\n        \"preprocessed\": request.withPP,\n        \"flags\": request.flags\n    };\n    return JSON.stringify(options);\n}\n\nfunction execute(fileName, request, protocolVersion, force) {\n    let options = {\n        timeout: TIMEOUT * 1000,\n        killSignal: 'SIGKILL'\n    };\n    return new Promise((resolve, reject) => {\n        console.time(fileName);\n        return exec(runDockerCommand(fileName, request, force), options, function (err, stdout, stderr) {\n            if (err) {\n                console.timeEnd(fileName);\n                console.log('Bench failed ' + fileName);\n                exec(\"./kill-docker \" + fileName);\n                reject(new BenchError(\"\\u001b[0m\\u001b[0;1;31mError or timeout\\u001b[0m\\u001b[1m<br>\" + stdout + \"<br>\" + stderr));\n            } else {\n                console.timeEnd(fileName);\n                console.log('Bench done ' + fileName + (stderr.indexOf('cached results') > -1 ? ' from cache' : ''));\n                resolve({\n                    res: fs.readFileSync(fileName + '.build', 'utf8'),\n                    includes: fs.readFileSync(fileName + '.inc', 'utf8'),\n                    asm: request.asm && request.asm.length > 0 ? fs.readFileSync(fileName + '.s', 'utf8') : null,\n                    preprocessed: request.withPP ? fs.readFileSync(fileName + '.i', 'utf8') : null,\n                    stdout: stderr,\n                    id: tools.encodeName(makeCodeName(request, protocolVersion)),\n                    title: request.title\n                });\n            }\n        });\n    });\n}\n\nfunction loadOptions(optionString) {\n    let options = JSON.parse(optionString);\n    if (options.cppVersion.length === 2) {\n        options.cppVersion = 'c++' + options.cppVersion;\n    }\n    if (!options.flags) {\n        options.flags = [];\n    }\n    return options;\n}\n\nfunction groupResults(results, id, name) {\n    let code = results[0];\n    let options = results[1];\n    let graph = results[2];\n    let includes = results[3];\n    let preprocessed = results[4];\n    let asm = results[5];\n    return { code: code, options: loadOptions(options), graph: graph, id: id, title: name, includes: includes, preprocessed: preprocessed, asm: asm };\n}\n\nfunction makeCodeName(tab, protocolVersion) {\n    if (protocolVersion === 4) {\n        return sha1(tab.code + tab.compiler + tab.optim + tab.cppVersion + tab.lib + tab.withPP + tab.asm + protocolVersion);\n    }\n    return sha1(tab.code + tab.compiler + tab.optim + tab.cppVersion + tab.lib + tab.withPP + tab.asm + protocolVersion + tab.flags.join(' '));\n}\n\nfunction makeName(request) {\n    return sha1(request.tabs.reduce(u, curr => u + makeCodeName(curr, request.protocolVersion)) + request.protocolVersion);\n}\n\nfunction filename(name) {\n    let dir = WRITE_PATH + '/' + name.substr(0, 2);\n    return dir + '/' + name;\n}\n\nasync function benchmarkOneBuild(tab, protocolVersion, force) {\n    try {\n        if (MAX_CODE_LENGTH > 0 && tab.code.length > MAX_CODE_LENGTH) {\n            return Promise.reject(`\\u001b[0m\\u001b[0;1;31mError: Unauthorized code length in {$unit.title}.\\u001b[0m\\u001b[1m`);\n        }\n        let name = makeCodeName(tab, protocolVersion);\n        console.log('Bench ' + name + ' < ' + optionsToString(tab, protocolVersion));\n        let fileName = filename(name);\n        await tools.write(fileName + '.cpp', tab.code);\n        await tools.write(fileName + '.opt', optionsToString(tab, protocolVersion));\n        return await execute(fileName, tab, protocolVersion, force);\n    } catch (e) {\n        if (e instanceof BenchError) {\n            return { stdout: e.message };\n        } else {\n            console.log(e);\n            return Promise.reject('Unexpected error while processing the benchmark, please contact the website owner');\n        }\n    }\n}\n\nasync function benchmark(request, header) {\n    return await Promise.all(request.tabs.map(u => benchmarkOneBuild(u, request.protocolVersion, request.force)));\n}\n\nasync function reloadOne(id, name) {\n    const fileName = filename(id);\n    const values = await Promise.all([tools.read(fileName + '.cpp'), tools.read(fileName + '.opt'), tools.read(fileName + '.build'), tools.read(fileName + '.inc'), tools.read(fileName + '.i', true), tools.read(fileName + '.s', true)]);\n    return groupResults(values, id, name);\n}\n\nasync function reload(encodedName) {\n    let fileName = filename(tools.decodeName(encodedName));\n    const ids = await tools.read(fileName + '.res');\n    return await Promise.all(ids.split(\"\\n\").map(s => {\n        const info = s.split(\"\\t\");\n        return reloadOne(tools.decodeName(info[0]), info[1]);\n    }));\n}\n\nfunction readBuildResults(values) {\n    if (!values.res) return {};\n    let results = values.res.split('\\n');\n    let times = [];\n    let memories = [];\n    let inputs = [];\n    let outputs = [];\n    let pagefaults = [];\n    for (let i = 0; i < results.length; i++) {\n        let s = results[i].split('\\t');\n        if (s.length === 7) {\n            times.push({ user: s[0], kernel: s[1] });\n            memories.push(s[2]);\n            inputs.push(s[3]);\n            outputs.push(s[4]);\n            pagefaults.push({ major: s[5], minor: s[6] });\n        }\n    }\n    return {\n        times: times,\n        memories: memories,\n        inputs: inputs,\n        outputs: outputs,\n        pagefaults: pagefaults\n    };\n}\n\nfunction makeBuildGraphResult(values) {\n    let result = values.map(v => readBuildResults(v));\n    let messages = values.map(v => v.stdout);\n    let includes = values.map(v => v.includes);\n    let asm = values.map(v => v.asm);\n    let preprocessed = values.map(v => v.preprocessed);\n    let idsList = values.map(v => `${v.id}\\t${v.title}`).reduce((r, v) => r + '\\n' + v);\n    let id = sha1(idsList);\n    tools.write(filename(id) + '.res', idsList);\n    return {\n        result: result,\n        messages: messages,\n        includes: includes,\n        asm: asm,\n        preprocessed: preprocessed,\n        id: tools.encodeName(id)\n    };\n}\n\nfunction makeOneRequest(done) {\n    return {\n        code: done.code,\n        compiler: done.options.compiler,\n        optim: done.options.optim,\n        cppVersion: done.options.cppVersion,\n        lib: done.options.lib,\n        protocolVersion: done.options.protocolVersion,\n        title: done.title,\n        flags: done.options.flags,\n    };\n}\n\nfunction getRequestAndResult(done) {\n    return Object.assign({ tabs: done.map(d => makeOneRequest(d)) }, makeBuildGraphResult(done.map(d => {\n        return {\n            res: d.graph,\n            stdout: '',\n            includes: d.includes,\n            asm: d.asm,\n            preprocessed: d.preprocessed,\n            id: tools.encodeName(d.id)\n        };\n    })));\n}\n\nfunction getEnv() {\n    return {\n        maxCodeLength: MAX_CODE_LENGTH,\n        timeout: TIMEOUT,\n        containers: AVAILABLE_CONTAINERS,\n        containerDl: ALLOW_CONTAINER_DOWNLOAD\n    };\n}\n\nexport {\n    listContainers as updateAvailableContainersList,\n    makeName, groupResults, optionsToString, execute, cleanFilename, makeBuildGraphResult, benchmark, reload,\n    getRequestAndResult, getEnv\n};\n"
  },
  {
    "path": "src/libquick.js",
    "content": "import { exec } from 'child_process';\nimport sha1 from 'sha1';\nimport fs from 'fs';\nimport * as tools from './tools.js';\nimport * as docker from './docker.js';\n\nconst MAX_CODE_LENGTH = process.env.QB_CODE_LIMIT || 20000;\nconst TIMEOUT = parseInt(process.env.QB_TIMEOUT, 10) < 0 ? 0 : (parseInt(process.env.QB_TIMEOUT, 10) || 120);\nconst ALLOW_CONTAINER_DOWNLOAD = process.env.ALLOW_CONTAINER_DOWNLOAD;\n\nconst WRITE_PATH = '/data';\nconst PREFIX_CODE_1 = `#include <benchmark/benchmark_api.h>\n`;\nconst SUFFIX_CODE_1 = `\n\nstatic void Noop(benchmark::State& state) {\n  while (state.KeepRunning());\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\nconst PREFIX_CODE_2 = `#include <benchmark/benchmark.h>\n`;\nconst SUFFIX_CODE_2 = `\n\nstatic void Noop(benchmark::State& state) {\n  for (auto _ : state) benchmark::DoNotOptimize(0);\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\nconst SUFFIX_CODE_3 = `\n\nstatic void Noop(benchmark::State& state) {\n  for (auto _ : state) benchmark::DoNotOptimize(0);\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN();`;\n\nvar AVAILABLE_CONTAINERS = [];\n\nclass BenchError extends Error{\n    constructor(message) {\n        super(message);\n        this.name = \"BenchError\";\n    }\n}\n\nasync function listContainers() {\n    AVAILABLE_CONTAINERS = [];\n    await docker.listContainers(AVAILABLE_CONTAINERS);\n}\n\nfunction runDockerCommand(fileName, request) {\n    return './run-docker ' + fileName + ' ' + request.options.compiler + ' ' + request.options.optim + ' ' + request.options.cppVersion + ' ' + (request.disassemblyOption || 'no') + ' ' + (request.force || false) + ' ' + (request.options.lib || 'gnu') + request.options.flags.join(' ');\n}\n\nfunction optionsToString(request) {\n    let options = {\n        protocolVersion: request.protocolVersion,\n        disassemblyOption: request.disassemblyOption,\n        compiler: request.options.compiler,\n        optim: request.options.optim,\n        cppVersion: request.options.cppVersion,\n        lib: request.options.lib,\n        flags: request.options.flags,\n    };\n    return JSON.stringify(options);\n}\n\nfunction execute(fileName, request) {\n    let options = {\n        timeout: TIMEOUT * 1000,\n        killSignal: 'SIGKILL'\n    };\n    return new Promise((resolve, reject) => {\n        console.time(fileName);\n        return exec(runDockerCommand(fileName, request), options, function (err, stdout, stderr) {\n            if (err) {\n                console.timeEnd(fileName);\n                console.log('Bench failed ' + fileName);\n                exec(\"./kill-docker \" + fileName);\n                reject(new BenchError(\"\\u001b[0m\\u001b[0;1;31mError or timeout\\u001b[0m\\u001b[1m<br>\" + stdout + \"<br>\" + stderr));\n            } else {\n                console.timeEnd(fileName);\n                console.log('Bench done ' + fileName + (stderr.indexOf('cached results') > -1 ? ' from cache' : ''));\n                const perfRecorded = !request.disassemblyOption.match(\"no\")\n                resolve({\n                    res: fs.readFileSync(fileName + '.out'),\n                    stdout: stderr,\n                    id: tools.encodeName(makeName(request)),\n                    annotation: perfRecorded? fs.readFileSync(fileName + '.perf', 'utf8') : null,\n\t\t\t\t\t\t\t\t\t\tdisassemblyOption: request.disassemblyOption,\n                });\n            }\n        });\n    });\n}\n\nfunction parseOptions(optionsString) {\n    let options = JSON.parse(optionsString);\n    if (options.cppVersion.length === 2) {\n        options.cppVersion = 'c++' + options.cppVersion;\n    }\n    if (!options.flags) {\n        options.flags = [];\n    }\n    return options;\n}\n\nfunction groupResults(results) {\n    let code = unwrapCode(results[0]);\n    let options = results[1];\n    let graph = results[2];\n    let annotation = results[3];\n    let parsedOptions = parseOptions(options);\n    let disassemblyOption = \"no\"\n    if (parsedOptions.disassemblyOption) {\n        disassemblyOption = parsedOptions.disassemblyOption;\n        delete parsedOptions.disassemblyOption;\n    } else if (parsedOptions.isAnnotated) {\n        disassemblyOption = \"att\";\n        delete parsedOptions.isAnnotated;\n    }\n    return { code: code, options: parsedOptions, graph: JSON.parse(graph), annotation: annotation, disassemblyOption: disassemblyOption };\n}\n\nfunction makeName(request) {\n    if (request.protocolVersion === 1)\n        return sha1(request.code + request.compiler + request.optim + request.cppVersion + request.protocolVersion);\n    if (request.protocolVersion === 2)\n        return sha1(request.code + request.compiler + request.optim + request.cppVersion + request.isAnnotated + request.protocolVersion);\n    if (request.protocolVersion === 3)\n        return sha1(request.code + request.compiler + request.optim + request.cppVersion + request.isAnnotated + request.protocolVersion + request.lib);\n    if (request.protocolVersion === 4)\n        return sha1(request.code + request.options.compiler + request.options.optim + request.options.cppVersion + request.isAnnotated + request.protocolVersion + request.options.lib);\n    return sha1(request.code + request.options.compiler + request.options.optim + request.options.cppVersion + request.disassemblyOption + request.protocolVersion + request.options.lib + request.options.flags.join(' '));\n}\n\nfunction wrapCode(inputCode) {\n    return PREFIX_CODE_2 + inputCode + SUFFIX_CODE_3;\n}\n\nfunction unwrapCode(inputCode) {\n    if (inputCode.startsWith(PREFIX_CODE_1)) {\n        inputCode = inputCode.slice(PREFIX_CODE_1.length);\n    }\n    if (inputCode.endsWith(SUFFIX_CODE_1)) {\n        inputCode = inputCode.slice(0, -SUFFIX_CODE_1.length);\n    }\n    if (inputCode.startsWith(PREFIX_CODE_2)) {\n        inputCode = inputCode.slice(PREFIX_CODE_2.length);\n    }\n    if (inputCode.endsWith(SUFFIX_CODE_2)) {\n        inputCode = inputCode.slice(0, -SUFFIX_CODE_2.length);\n    }\n    if (inputCode.endsWith(SUFFIX_CODE_3)) {\n        inputCode = inputCode.slice(0, -SUFFIX_CODE_3.length);\n    }\n    return inputCode;\n}\n\nfunction getFunctions(code) {\n    const RE = /BENCHMARK\\s*\\(\\s*([A-Za-z0-9_]+)\\s*\\)/g;\n    let content = '';\n    let res;\n    while ((res = RE.exec(code)) !== null) {\n        content += res[1] + '\\n';\n    }\n    return content;\n}\n\nasync function benchmark(request, header) {\n    try {\n        if (MAX_CODE_LENGTH > 0 && request.code.length > MAX_CODE_LENGTH) {\n            return Promise.reject('\\u001b[0m\\u001b[0;1;31mError: Unauthorized code length.\\u001b[0m\\u001b[1m');\n        }\n        let name = makeName(request);\n        console.log('Bench ' + name + ' ' + JSON.stringify(header) + ' < ' + optionsToString(request));\n        var dir = WRITE_PATH + '/' + name.substr(0, 2);\n        var fileName = dir + '/' + name;\n        await tools.write(fileName + '.cpp', wrapCode(request.code));\n        await tools.write(fileName + '.func', getFunctions(request.code));\n        await tools.write(fileName + '.opt', optionsToString(request));\n        return await execute(fileName, request);\n    } catch (e) {\n        if (e instanceof BenchError) {\n            return { stdout: e.message };\n        } else {\n            console.log(e);\n            return Promise.reject('Unexpected error while processing the benchmark, please contact the website owner');\n        }\n    }\n}\n\nasync function reload(encodedName) {\n    let name = tools.decodeName(encodedName);\n    var dir = WRITE_PATH + '/' + name.substr(0, 2);\n    var fileName = dir + '/' + name;\n    let values = await Promise.all([tools.read(fileName + '.cpp'), tools.read(fileName + '.opt'), tools.read(fileName + '.out'), tools.read(fileName + '.perf', true)])\n    return groupResults(values);\n}\n\nfunction makeGraphResult(values, message, id, annotation, disassemblyOption) {\n    let result = {};\n    if (values) {\n        result = { context: values.context };\n        const noopTime = values.benchmarks[values.benchmarks.length - 1].cpu_time;\n        result.benchmarks = values.benchmarks.map(obj => {\n            return {\n                name: obj.name,\n                cpu_time: obj.cpu_time / noopTime\n            };\n        });\n    }\n    return { result: result, message: message, id: id, annotation: annotation, disassemblyOption: disassemblyOption};\n}\n\nfunction makeRequest(done) {\n    return {\n        code: done.code,\n        options: {\n            compiler: done.options.compiler,\n            optim: done.options.optim,\n            cppVersion: done.options.cppVersion,\n            lib: done.options.lib,\n            flags: done.options.flags\n        },\n        disassemblyOption: done.options.disassemblyOption,\n        protocolVersion: done.options.protocolVersion\n    };\n}\nfunction getRequestAndResult(done) {\n    const request = makeRequest(done);\n    return Object.assign({ tab: request }, makeGraphResult(done.graph, '', tools.encodeName(makeName(request)), done.annotation, done.disassemblyOption));\n}\n\nfunction getEnv() {\n    return {\n        maxCodeLength: MAX_CODE_LENGTH,\n        timeout: TIMEOUT,\n        containers: AVAILABLE_CONTAINERS,\n        containerDl: ALLOW_CONTAINER_DOWNLOAD\n    };\n}\n\nexport {\n    listContainers as updateAvailableContainersList,\n    makeName, wrapCode, unwrapCode, groupResults, getFunctions, optionsToString, execute, benchmark, makeGraphResult,\n    reload, makeRequest, getRequestAndResult, getEnv\n};\n"
  },
  {
    "path": "src/tools.js",
    "content": "import fs from 'fs';\n\nfunction write(fileName, code) {\n    return new Promise((resolve, reject) => {\n        fs.writeFile(fileName, code, (err) => {\n            if (err) {\n                reject(err);\n            } else {\n                resolve();\n            }\n        });\n    });\n}\n\nfunction read(fileName, acceptMissing) {\n    return new Promise((resolve, reject) => {\n        fs.readFile(fileName, 'utf8', (err, data) => {\n            if (err) {\n                if (acceptMissing && err.code === 'ENOENT') {\n                    resolve(null);\n                } else {\n                    reject(err);\n                }\n            } else {\n                resolve(data);\n            }\n        });\n    });\n}\n\nfunction encodeName(id) {\n    let short = Buffer.from(id, 'hex').toString('base64');\n    short = short.replace(new RegExp('/', 'g'), '-').replace(new RegExp('\\\\+', 'g'), '_');\n    return short.slice(0, -1);\n}\n\nfunction decodeName(short) {\n    short = short.replace(new RegExp('\\\\-', 'g'), '/').replace(new RegExp('_', 'g'), '+ ') + '=';\n    return Buffer.from(short, 'base64').toString('hex');\n}\n\nexport {read, write, encodeName, decodeName};\n"
  },
  {
    "path": "system-test/build/test.cpp",
    "content": "#include <cstdio>\n\nint main() {\n   puts(\"Hello World\");\n   return 0;\n}\n"
  },
  {
    "path": "system-test/build.js",
    "content": "import * as libbuild from '../src/libbuild.js';\nimport { expect } from 'chai';\nimport fs from 'fs';\n\nconst version = process.env.QB_VERSION;\n\nfunction removeIfExists(path) {\n    try {\n        fs.unlinkSync(path);\n    } catch (ignore) {\n        //ignore\n    }\n}\n\ndescribe('run build-bench', function () {\n    before(function () {\n        removeIfExists('./system-test/build/test.lock');\n    });\n\n    it('should have build results', async () => {\n        const request = {\n            compiler: version,\n            optim: 3,\n            cppVersion: 'c++1z',\n            lib: \"gnu\",\n            title: \"cstdio\",\n            asm: \"att\",\n            withPP: true,\n            flags: []\n        };\n        expect(version).to.be.ok;\n        const done = await libbuild.execute('system-test/build/test', request, 3, true);\n        // Time results are rows of 7 elements separated by tabs\n        expect(done.res.split('\\n')).to.have.lengthOf.above(1);\n        expect(done.res.split('\\n')[0].split('\\t')).to.have.length(7);\n\n        // There should be includes\n        expect(done.includes.split('\\n')).to.have.lengthOf.above(1);\n        expect(done.includes).to.have.string('cstdio');\n\n        // There should be assembly\n        expect(done.asm.split('\\n')).to.have.lengthOf.above(1);\n        expect(done.asm).to.have.string('cstdio');\n\n        // There should be preprocessed code\n        expect(done.preprocessed.split('\\n')).to.have.lengthOf.above(1);\n        expect(done.preprocessed).to.have.string('cstdio');\n\n        expect(done.title).to.equal('cstdio');\n    }).timeout(120000);\n\n    after(function () {\n        removeIfExists('./system-test/build/test.build');\n        removeIfExists('./system-test/build/test.i');\n        removeIfExists('./system-test/build/test.inc');\n        removeIfExists('./system-test/build/test.s');\n    });\n});\n"
  },
  {
    "path": "system-test/env/version.cpp",
    "content": "#include <iostream>\n\nint main() {\n#ifdef __clang__\n   std::cout << \"clang-\" << __clang_major__ << \".\" << __clang_minor__;\n#else\n   std::cout << \"gcc-\" << __GNUC__ << \".\" << __GNUC_MINOR__;\n#endif\n   return 0;\n}\n"
  },
  {
    "path": "system-test/env.js",
    "content": "import { expect } from 'chai';\nimport { exec } from 'child_process';\nimport { fileURLToPath } from 'url';\nimport { dirname } from 'path';\n\nconst version = process.env.QB_VERSION;\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\ndescribe('check compiler version inside docker', function () {\n    it('should have the same version', async () => {\n        let options = {\n            timeout: 60000,\n            killSignal: 'SIGKILL'\n        };\n        const result = await new Promise((resolve, reject) => exec(`docker run --rm -v ${__dirname}/env/version.cpp:/home/builder/bench-file.cpp -t fredtingaud/quick-bench:${version} /bin/bash -c \"./build && ./run\"`, options, (err, stdout, stderr) => {\n            if (err) {\n                reject(stderr);\n            } else {\n                resolve(stdout);\n            }\n        }));\n        expect(result).to.eql(version);\n    }).timeout(60000);\n});\n\ndescribe('check available flags', function () {\n    it('should contain multiple standards', async () => {\n        let options = {\n            timeout: 60000,\n            killSignal: 'SIGKILL'\n        };\n        const result = await new Promise((resolve, reject) => exec(`docker run --rm -t fredtingaud/quick-bench:${version} /bin/bash -c \"./about-me\"`, options, (err, stdout, stderr) => {\n            if (err) {\n                reject(stdout);\n            } else {\n                resolve(stdout);\n            }\n        }));\n        // No idea why but despite the whole chain being unix talking to unix, we get a bunch of \\r in chai results.\n        expect(result.replaceAll('\\r', '')).to.be.a('string').and.satisfy(msg => msg.startsWith('[version]\\n1\\n[std]'));\n        expect(result).to.have.string('c++11');\n        expect(result).to.have.string('[experimental]');\n    }).timeout(60000);\n})\n"
  },
  {
    "path": "system-test/quick/test.cpp",
    "content": "#include <benchmark/benchmark.h>\n#include <vector>\n#include <algorithm>\n#include <range/v3/all.hpp>\n\nstatic void BM_StringCreation(benchmark::State& state) {\n  std::vector<int> a = {4, 5, 0, 1, -5};\n  while (state.KeepRunning())\n    {\n      auto v = a;\n      std::sort( v.begin(), v.end() );\n    }\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\n// Define another benchmark\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::vector<int> a = {4, 5, 0, 1, -5};\n  while (state.KeepRunning())\n    {\n      auto v = a;\n      ranges::sort( v );\n    }\n}\nBENCHMARK(BM_StringCopy);\n\nBENCHMARK_MAIN();\n"
  },
  {
    "path": "system-test/quick/test.func",
    "content": "BM_StringCreation\nBM_StringCopy\n"
  },
  {
    "path": "system-test/quick.js",
    "content": "import * as libquick from '../src/libquick.js';\nimport { expect } from 'chai';\nimport fs from 'fs';\n\nconst version = process.env.QB_VERSION;\n\nfunction removeIfExists(path) {\n    try {\n        fs.unlinkSync(path);\n    } catch (ignore) {\n        //ignore\n    }\n}\n\ndescribe('run docker with version', function () {\n    before(function () {\n        removeIfExists('./system-test/quick/test.lock');\n    });\n\n    it('should have benchmark results', async () => {\n        const request = {\n            options: {\n                compiler: version,\n                optim: 3,\n                cppVersion: \"c++1z\",\n                lib: \"gnu\",\n                flags: []\n            },\n            disassemblyOption: \"att\",\n            force: \"true\"\n        };\n        expect(version).to.be.ok;\n        const done = await libquick.execute('system-test/quick/test', request);\n        const parsed = JSON.parse(done.res);\n        expect(parsed.benchmarks).to.have.length(2);\n        expect(done.annotation).to.be.ok;\n        expect(done.annotation.split('\\n')).to.have.lengthOf.above(7);\n        expect(done.annotation).to.have.string('BM_StringCreation');\n        expect(done.annotation).to.have.string('BM_StringCopy');\n        //\texpect(done.stdout).to.be.empty; // Removed because of a Docker message on my Ubuntu version.\n        console.log(done.stdout);\n        expect(done.annotation).to.be.ok;\n    }).timeout(120000);\n\n    if (version.startsWith('clang')) {\n        it('should have benchmark results with libcxx', async () => {\n            const request = {\n                options: {\n                    compiler: version,\n                    optim: 3,\n                    cppVersion: \"c++1z\",\n                    lib: \"llvm\",\n                    flags: []\n                },\n                disassemblyOption: \"att\",\n                force: \"true\"\n            };\n            expect(version).to.be.ok;\n            const done = await libquick.execute('system-test/quick/test', request);\n            const parsed = JSON.parse(done.res);\n            expect(parsed.benchmarks).to.have.length(2);\n            expect(done.annotation).to.be.ok;\n            expect(done.annotation.split('\\n')).to.have.lengthOf.above(7);\n            expect(done.annotation).to.have.string('BM_StringCreation');\n            expect(done.annotation).to.have.string('BM_StringCopy');\n            //\texpect(done.stdout).to.be.empty; // Removed because of a Docker message on my Ubuntu version.\n            console.log(done.stdout);\n            expect(done.annotation).to.be.ok;\n        }).timeout(120000);\n    }\n\n    after(function () {\n        removeIfExists('./system-test/quick/test.out');\n        removeIfExists('./system-test/quick/test.perf');\n    });\n});\n"
  },
  {
    "path": "test/clean-filename.test.js",
    "content": "﻿import * as app from '../src/libbuild.js';\n\nimport assert from 'assert';\n\ndescribe('clean unwanted characters', function () {\n    it('should keep words', function () {\n        assert.equal(app.cleanFilename('cstdio'), 'cstdio');\n    });\n    it('should keep - and _', function () {\n        assert.equal(app.cleanFilename('c_str-1'), 'c_str-1');\n    });\n    it('should not keep unwanted characters', function () {\n        assert.equal(app.cleanFilename('c/test\\t\\nunwanted./**/$^%'), 'c_test__unwanted________');\n    });\n    it('should not keep emojis', function () {\n        assert.equal(app.cleanFilename('😊'), '__');\n    });\n    it('should have a name', function () {\n        assert.equal(app.cleanFilename(''), '_');\n    });\n});\n"
  },
  {
    "path": "test/code.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\n\nimport assert from 'assert';\n\nconst startCode = `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`;\n\nconst code1 = `#include <benchmark/benchmark_api.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  while (state.KeepRunning());\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\n\nconst code2 = `#include <benchmark/benchmark.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  for (auto _ : state) benchmark::DoNotOptimize(0);\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\n\nconst code3 = `#include <benchmark/benchmark.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  for (auto _ : state) benchmark::DoNotOptimize(0);\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN();`;\n\ndescribe('symetrical', function () {\n    it('should return initial value when wrapping then unwrapping', function () {\n        assert.equal(libquick.unwrapCode(libquick.wrapCode(startCode)), startCode);\n    });\n    it('should return initial value when unwrapping a v1 code', function () {\n        assert.equal(libquick.unwrapCode(code1), startCode);\n    });\n    it('should return initial value when unwrapping a v2 code', function () {\n        assert.equal(libquick.unwrapCode(code2), startCode);\n    });\n    it('should return initial value when unwrapping a v3 code', function () {\n        assert.equal(libquick.unwrapCode(code3), startCode);\n    });\n})"
  },
  {
    "path": "test/containers-list.test.js",
    "content": "import * as app from '../src/docker.js';\n\nimport assert from 'assert';\n\n\n\ndescribe('list containers list', function () {\n    it('should support empty list', function () {\n        assert.deepEqual(app.readContainersList(''), []);\n    });\n    it('should parse one value', function () {\n        assert.deepEqual(app.readContainersList('clang-10.1'), ['clang-10.1']);\n    });\n    it('should order by decreasing version', function () {\n        assert.deepEqual(app.readContainersList('clang-10.1\\nclang-8.1\\nclang-9.0'), ['clang-10.1', 'clang-9.0', 'clang-8.1']);\n    });\n    it('should sort clang first and gcc next', function () {\n        assert.deepEqual(app.readContainersList('clang-10.1\\ngcc-9.1\\nclang-9.0\\ngcc-12.7'), ['clang-10.1', 'clang-9.0', 'gcc-12.7', 'gcc-9.1']);\n    });\n});\n"
  },
  {
    "path": "test/getFunctions.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\n\nimport assert from 'assert';\n\nconst startCode = `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`;\n\nconst repeatCode = `\nstatic void CopyStrings(benchmark::State& state) {\n  while (state.KeepRunning())\n    benchmark::DoNotOptimize(std::string(state.range(0), 'x'));\n}\nBENCHMARK(CopyStrings)->Arg(5)->Arg(10)->Arg(15)->Arg(16)->Arg(20)->Arg(25);\n`;\n\nconst spacesCode = `\nBENCHMARK( A);\nBENCHMARK(B );\nBENCHMARK( C );\nBENCHMARK( D D );\nBENCHMARK   (E);\n`\n\ndescribe('Find functions', function () {\n    it('should find simple functions', function () {\n        assert.equal(libquick.getFunctions(startCode), 'BM_StringCreation\\nBM_StringCopy\\n');\n    });\n    it('should find repeated benchmarks', function () {\n        assert.equal(libquick.getFunctions(repeatCode), 'CopyStrings\\n');\n    });\n    it('should support spaces arround name', function () {\n        assert.equal(libquick.getFunctions(spacesCode), 'A\\nB\\nC\\nE\\n');\n    });\n})\n"
  },
  {
    "path": "test/getv1.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\n\nimport assert from 'assert';\n\nconst OPTIONS = '{\"protocolVersion\":1,\"compiler\":\"clang++-3.8\",\"optim\":\"1\",\"cppVersion\":\"17\"}';\nconst OUTPUT = `{\n  \"context\": {\n    \"date\": \"2017-06-03 16:27:30\",\n    \"num_cpus\": 1,\n    \"mhz_per_cpu\": 2400,\n    \"cpu_scaling_enabled\": false,\n    \"library_build_type\": \"release\"\n  },\n  \"benchmarks\": [\n    {\n      \"name\": \"BM_StringCreation\",\n      \"iterations\": 110509442,\n      \"real_time\": 25,\n      \"cpu_time\": 6,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"BM_StringCopy\",\n      \"iterations\": 32549672,\n      \"real_time\": 86,\n      \"cpu_time\": 22,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"Noop\",\n      \"iterations\": 250612168,\n      \"real_time\": 11,\n      \"cpu_time\": 3,\n      \"time_unit\": \"ns\"\n    }\n  ]\n}`;\nconst INPUT = `#include <benchmark/benchmark_api.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  while (state.KeepRunning());\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\nconst EXPECTED = {\n    code: `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`,\n    graph: {\n        benchmarks: [\n            {\n                \"cpu_time\": 6,\n                \"iterations\": 110509442,\n                \"name\": \"BM_StringCreation\",\n                \"real_time\": 25,\n                \"time_unit\": \"ns\"\n            },\n            {\n                \"cpu_time\": 22,\n                \"iterations\": 32549672,\n                \"name\": \"BM_StringCopy\",\n                \"real_time\": 86,\n                \"time_unit\": \"ns\",\n            },\n            {\n                \"cpu_time\": 3,\n                \"iterations\": 250612168,\n                \"name\": \"Noop\",\n                \"real_time\": 11,\n                \"time_unit\": \"ns\"\n            },\n        ],\n        context: {\n            cpu_scaling_enabled: false,\n            date: \"2017-06-03 16:27:30\",\n            library_build_type: \"release\",\n            mhz_per_cpu: 2400,\n            num_cpus: 1\n        }\n    },\n    options: {\n        compiler: \"clang++-3.8\",\n        cppVersion: \"c++17\",\n        optim: \"1\",\n        flags: [],\n        protocolVersion: 1\n    },\n    disassemblyOption: \"no\",\n    annotation: undefined\n};\n\ndescribe('Return v1 stored file', function () {\n    it('should return a stable message with protocol 1', function () {\n        return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT]), EXPECTED);\n    });\n});\n"
  },
  {
    "path": "test/getv2.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\n\nimport assert from 'assert';\n\nconst OPTIONS = '{\"protocolVersion\":2,\"compiler\":\"clang++-3.8\",\"optim\":\"1\",\"cppVersion\":\"17\",\"isAnnotated\":true}';\nconst OUTPUT = `{\n  \"context\": {\n    \"date\": \"2017-06-03 16:27:30\",\n    \"num_cpus\": 1,\n    \"mhz_per_cpu\": 2400,\n    \"cpu_scaling_enabled\": false,\n    \"library_build_type\": \"release\"\n  },\n  \"benchmarks\": [\n    {\n      \"name\": \"BM_StringCreation\",\n      \"iterations\": 110509442,\n      \"real_time\": 25,\n      \"cpu_time\": 6,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"BM_StringCopy\",\n      \"iterations\": 32549672,\n      \"real_time\": 86,\n      \"cpu_time\": 22,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"Noop\",\n      \"iterations\": 250612168,\n      \"real_time\": 11,\n      \"cpu_time\": 3,\n      \"time_unit\": \"ns\"\n    }\n  ]\n}`;\nconst ANNOTATION = 'Some annotations.';\nconst INPUT = `#include <benchmark/benchmark_api.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  while (state.KeepRunning());\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\nconst EXPECTED = {\n    code: `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`,\n    graph: {\n        benchmarks: [\n            {\n                \"cpu_time\": 6,\n                \"iterations\": 110509442,\n                \"name\": \"BM_StringCreation\",\n                \"real_time\": 25,\n                \"time_unit\": \"ns\"\n            },\n            {\n                \"cpu_time\": 22,\n                \"iterations\": 32549672,\n                \"name\": \"BM_StringCopy\",\n                \"real_time\": 86,\n                \"time_unit\": \"ns\",\n            },\n            {\n                \"cpu_time\": 3,\n                \"iterations\": 250612168,\n                \"name\": \"Noop\",\n                \"real_time\": 11,\n                \"time_unit\": \"ns\"\n            },\n        ],\n        context: {\n            cpu_scaling_enabled: false,\n            date: \"2017-06-03 16:27:30\",\n            library_build_type: \"release\",\n            mhz_per_cpu: 2400,\n            num_cpus: 1\n        }\n    },\n    options: {\n        compiler: \"clang++-3.8\",\n        cppVersion: \"c++17\",\n        optim: \"1\",\n        flags: [],\n        protocolVersion: 2\n    },\n    disassemblyOption: \"att\",\n    annotation: \"Some annotations.\"\n};\n\ndescribe('Return v2 stored file', function () {\n    it('should return a stable message with protocol 2', function () {\n        return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT, ANNOTATION]), EXPECTED);\n    });\n});\n"
  },
  {
    "path": "test/getv3.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\n\nimport assert from 'assert';\n\nconst OPTIONS = '{\"protocolVersion\":3,\"compiler\":\"clang-9.1\",\"optim\":\"1\",\"cppVersion\":\"17\",\"isAnnotated\":true,\"lib\":\"llvm\"}';\nconst OUTPUT = `{\n  \"context\": {\n    \"date\": \"2017-06-03 16:27:30\",\n    \"num_cpus\": 1,\n    \"mhz_per_cpu\": 2400,\n    \"cpu_scaling_enabled\": false,\n    \"library_build_type\": \"release\"\n  },\n  \"benchmarks\": [\n    {\n      \"name\": \"BM_StringCreation\",\n      \"iterations\": 110509442,\n      \"real_time\": 25,\n      \"cpu_time\": 6,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"BM_StringCopy\",\n      \"iterations\": 32549672,\n      \"real_time\": 86,\n      \"cpu_time\": 22,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"Noop\",\n      \"iterations\": 250612168,\n      \"real_time\": 11,\n      \"cpu_time\": 3,\n      \"time_unit\": \"ns\"\n    }\n  ]\n}`;\nconst ANNOTATION = 'Some annotations.';\nconst INPUT = `#include <benchmark/benchmark_api.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  while (state.KeepRunning());\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\nconst EXPECTED = {\n    code: `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`,\n    graph: {\n        benchmarks: [\n            {\n                \"cpu_time\": 6,\n                \"iterations\": 110509442,\n                \"name\": \"BM_StringCreation\",\n                \"real_time\": 25,\n                \"time_unit\": \"ns\"\n            },\n            {\n                \"cpu_time\": 22,\n                \"iterations\": 32549672,\n                \"name\": \"BM_StringCopy\",\n                \"real_time\": 86,\n                \"time_unit\": \"ns\",\n            },\n            {\n                \"cpu_time\": 3,\n                \"iterations\": 250612168,\n                \"name\": \"Noop\",\n                \"real_time\": 11,\n                \"time_unit\": \"ns\"\n            },\n        ],\n        context: {\n            cpu_scaling_enabled: false,\n            date: \"2017-06-03 16:27:30\",\n            library_build_type: \"release\",\n            mhz_per_cpu: 2400,\n            num_cpus: 1\n        }\n    },\n    options: {\n        compiler: \"clang-9.1\",\n        cppVersion: \"c++17\",\n        optim: \"1\",\n        lib: \"llvm\",\n        flags: [],\n        protocolVersion: 3\n    },\n    disassemblyOption: \"att\",\n    annotation: \"Some annotations.\"\n};\n\ndescribe('Return v3 stored file', function () {\n    it('should return a stable message with protocol 3', function () {\n        return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT, ANNOTATION]), EXPECTED);\n    });\n});\n"
  },
  {
    "path": "test/getv4.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\n\nimport assert from 'assert';\n\nconst OPTIONS = '{\"protocolVersion\":4, \"compiler\":\"clang-9.0\",\"optim\":\"3\",\"cppVersion\":\"17\",\"lib\":\"llvm\",\"isAnnotated\":true}';\nconst OUTPUT = `{\n  \"context\": {\n    \"date\": \"2017-06-03 16:27:30\",\n    \"num_cpus\": 1,\n    \"mhz_per_cpu\": 2400,\n    \"cpu_scaling_enabled\": false,\n    \"library_build_type\": \"release\"\n  },\n  \"benchmarks\": [\n    {\n      \"name\": \"BM_StringCreation\",\n      \"iterations\": 110509442,\n      \"real_time\": 25,\n      \"cpu_time\": 6,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"BM_StringCopy\",\n      \"iterations\": 32549672,\n      \"real_time\": 86,\n      \"cpu_time\": 22,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"Noop\",\n      \"iterations\": 250612168,\n      \"real_time\": 11,\n      \"cpu_time\": 3,\n      \"time_unit\": \"ns\"\n    }\n  ]\n}`;\nconst ANNOTATION = 'Some annotations.';\nconst INPUT = `#include <benchmark/benchmark_api.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  while (state.KeepRunning());\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\nconst EXPECTED = {\n    code: `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`,\n    graph: {\n        benchmarks: [\n            {\n                \"cpu_time\": 6,\n                \"iterations\": 110509442,\n                \"name\": \"BM_StringCreation\",\n                \"real_time\": 25,\n                \"time_unit\": \"ns\"\n            },\n            {\n                \"cpu_time\": 22,\n                \"iterations\": 32549672,\n                \"name\": \"BM_StringCopy\",\n                \"real_time\": 86,\n                \"time_unit\": \"ns\",\n            },\n            {\n                \"cpu_time\": 3,\n                \"iterations\": 250612168,\n                \"name\": \"Noop\",\n                \"real_time\": 11,\n                \"time_unit\": \"ns\"\n            },\n        ],\n        context: {\n            cpu_scaling_enabled: false,\n            date: \"2017-06-03 16:27:30\",\n            library_build_type: \"release\",\n            mhz_per_cpu: 2400,\n            num_cpus: 1\n        }\n    },\n    options: {\n        compiler: \"clang-9.0\",\n        cppVersion: \"c++17\",\n        optim: \"3\",\n        lib: \"llvm\",\n        flags: [],\n        protocolVersion: 4\n    },\n    disassemblyOption: \"att\",\n    annotation: \"Some annotations.\"\n};\n\ndescribe('Return v4 stored file', function () {\n    it('should return a stable message with protocol 4', function () {\n        return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT, ANNOTATION]), EXPECTED);\n    });\n});\n"
  },
  {
    "path": "test/getv5.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\nimport * as libbuild from '../src/libbuild.js';\n\nimport assert from 'assert';\n\nconst OPTIONS = '{\"protocolVersion\":5, \"compiler\":\"clang-17.0\",\"optim\":\"3\",\"cppVersion\":\"c++17\",\"lib\":\"llvm\",\"flags\":[\"-ftest\"],\"disassemblyOption\":\"att\"}';\nconst OUTPUT = `{\n  \"context\": {\n    \"date\": \"2017-06-03 16:27:30\",\n    \"num_cpus\": 1,\n    \"mhz_per_cpu\": 2400,\n    \"cpu_scaling_enabled\": false,\n    \"library_build_type\": \"release\"\n  },\n  \"benchmarks\": [\n    {\n      \"name\": \"BM_StringCreation\",\n      \"iterations\": 110509442,\n      \"real_time\": 25,\n      \"cpu_time\": 6,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"BM_StringCopy\",\n      \"iterations\": 32549672,\n      \"real_time\": 86,\n      \"cpu_time\": 22,\n      \"time_unit\": \"ns\"\n    },\n    {\n      \"name\": \"Noop\",\n      \"iterations\": 250612168,\n      \"real_time\": 11,\n      \"cpu_time\": 3,\n      \"time_unit\": \"ns\"\n    }\n  ]\n}`;\nconst ANNOTATION = 'Some annotations.';\nconst INPUT = `#include <benchmark/benchmark_api.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  while (state.KeepRunning());\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`;\nconst PREPROCESSED = `        .text\n.file   \"cstdio.cpp\"\n.globl  main                            # -- Begin function main\n.p2align        4, 0x90\n.type   main,@function\nmain:                                   # @main\n.cfi_startproc`;\nconst GRAPH = `0.01    0.01    75492   856     8       6       3975\n0.01    0.01    74984   600     8       4       3966\n0.03    0.00    75608   600     8       4       3975\n0.03    0.00    75752   600     8       4       3985\n0.01    0.01    75428   600     8       4       3972`;\nconst INCLUDES = `. /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/cstdio\n.. /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/c++config.h\n... /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/os_defines.h\n.... /usr/include/features.h\n..... /usr/include/features-time64.h\n...... /usr/include/x86_64-linux-gnu/bits/wordsize.h\n...... /usr/include/x86_64-linux-gnu/bits/timesize.h\n....... /usr/include/x86_64-linux-gnu/bits/wordsize.h\n..... /usr/include/stdc-predef.h\n..... /usr/include/x86_64-linux-gnu/sys/cdefs.h\n...... /usr/include/x86_64-linux-gnu/bits/wordsize.h\n...... /usr/include/x86_64-linux-gnu/bits/long-double.h\n..... /usr/include/x86_64-linux-gnu/gnu/stubs.h\n...... /usr/include/x86_64-linux-gnu/gnu/stubs-64.h\n... /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/cpu_defines.h\n... /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/pstl/pstl_config.h\n.. /usr/include/stdio.h`;\nconst EXPECTED = {\n    code: `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`,\n    graph: {\n        benchmarks: [\n            {\n                \"cpu_time\": 6,\n                \"iterations\": 110509442,\n                \"name\": \"BM_StringCreation\",\n                \"real_time\": 25,\n                \"time_unit\": \"ns\"\n            },\n            {\n                \"cpu_time\": 22,\n                \"iterations\": 32549672,\n                \"name\": \"BM_StringCopy\",\n                \"real_time\": 86,\n                \"time_unit\": \"ns\",\n            },\n            {\n                \"cpu_time\": 3,\n                \"iterations\": 250612168,\n                \"name\": \"Noop\",\n                \"real_time\": 11,\n                \"time_unit\": \"ns\"\n            },\n        ],\n        context: {\n            cpu_scaling_enabled: false,\n            date: \"2017-06-03 16:27:30\",\n            library_build_type: \"release\",\n            mhz_per_cpu: 2400,\n            num_cpus: 1\n        }\n    },\n    options: {\n        compiler: \"clang-17.0\",\n        cppVersion: \"c++17\",\n        optim: \"3\",\n        lib: \"llvm\",\n        flags: [\"-ftest\"],\n        protocolVersion: 5\n    },\n    disassemblyOption: \"att\",\n    annotation: \"Some annotations.\"\n};\n\nconst EXPECTED_BB = {\n  code: `#include <benchmark/benchmark_api.h>\nstatic void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n\n\nstatic void Noop(benchmark::State& state) {\n  while (state.KeepRunning());\n}\nBENCHMARK(Noop);\nBENCHMARK_MAIN()`,\n  graph: GRAPH,\n  includes: INCLUDES,\n  options: {\n      compiler: \"clang-17.0\",\n      cppVersion: \"c++17\",\n      optim: \"3\",\n      lib: \"llvm\",\n      flags: [\"-ftest\"],\n      disassemblyOption: \"att\",\n      protocolVersion: 5\n  },\n  preprocessed: PREPROCESSED,\n  asm: \"Some annotations.\",\n  id: \"id\",\n  title: \"filename\"\n};\n\ndescribe('Return v5 stored file', function () {\n  it('QB: should return a stable message with protocol 5', function () {\n    return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT, ANNOTATION]), EXPECTED);\n  });\n  it('BB: should return a stable message with protocol 5', function () {\n    return assert.deepEqual(libbuild.groupResults([INPUT, OPTIONS, GRAPH, INCLUDES, PREPROCESSED, ANNOTATION], 'id', 'filename'), EXPECTED_BB);\n  });\n});\n"
  },
  {
    "path": "test/id.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\n\nimport assert from 'assert';\n\nconst startCode = `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`;\nconst compiler = 'clang++-3.8';\nconst cppVersion = 17;\nconst optim = 1;\n\ndescribe('id version 1', function () {\n    it('should return a stable id', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, protocolVersion: 1 }), '630d398cbd8e8c9d76bd3fb17ede3b77abe4302e');\n    });\n    it('should return different id on optim change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: \"0\", cppVersion: cppVersion, protocolVersion: 1 }), '1fc0b826d2aaf85cceb587ba9960638b0d36ed74');\n    });\n    it('should return different id on code change', function () {\n        assert.equal(libquick.makeName({ code: 'hello', compiler: compiler, optim: optim, cppVersion: cppVersion, protocolVersion: 1 }), 'e7b57d1778e7b38505a3581971eb8435bced36ae');\n    });\n    it('should return different id on compiler change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: 'clang++-4.0', optim: optim, cppVersion: cppVersion, protocolVersion: 1 }), '5dee5060303d5a795b2154d76f87718f8aa7dbdf');\n    });\n    it('should return different id on cppVersion change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: '98', protocolVersion: 1 }), '1aa1a9c43024dd01eb50f8b42832218f8d4299d9');\n    });\n})\n\ndescribe('id version 2', function () {\n    it('should return different id on protocolVersion change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, protocolVersion: 2 }), '79521ea600940e871ab08a602b355849706871de');\n    });\n    it('should return different id on optim change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: \"0\", cppVersion: cppVersion, isAnnotated: true, protocolVersion: 2 }), 'a60edbed043f9271eb8f2ac33e48ba836d33f6eb');\n    });\n    it('should return different id on code change', function () {\n        assert.equal(libquick.makeName({ code: 'hello', compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, protocolVersion: 2 }), '878de5d52c012f1c6469af9273510412a3607ab8');\n    });\n    it('should return different id on compiler change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: 'clang++-4.0', optim: optim, cppVersion: cppVersion, isAnnotated: true, protocolVersion: 2 }), '02da5f0e209d2370f0546b5919c754d577a67af9');\n    });\n    it('should return different id on cppVersion change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: '98', isAnnotated: true, protocolVersion: 2 }), 'c2c8ca7553725f561c05120804638d44318825f6');\n    });\n    it('should return different id on annotation change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: false, protocolVersion: 2 }), '5ccde87699ed42859925307950ec7ce2c2197ddc');\n    });\n})\n\ndescribe('id version 3', function () {\n    it('should return different id on protocolVersion change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), 'a53c5b14856c39c55439218c10320bef4a49257c');\n    });\n    it('should return different id on optim change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: \"0\", cppVersion: cppVersion, isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), '6b208fee183ba8884aa62a025f9e07308c6aa757');\n    });\n    it('should return different id on code change', function () {\n        assert.equal(libquick.makeName({ code: 'hello', compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), 'b1a20c68ed6ccf1f68c5cae88ca96b559d260dc4');\n    });\n    it('should return different id on compiler change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: 'clang++-4.0', optim: optim, cppVersion: cppVersion, isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), '0b17798be35cd859202da65dee74301ae048cf2f');\n    });\n    it('should return different id on cppVersion change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: '98', isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), '77aff1de87af423078b44330ce0e002b53a8ae24');\n    });\n    it('should return different id on annotation change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: false, lib: 'gnu', protocolVersion: 3 }), '390203c96b49407964a8973bb51f5ee87156b045');\n    });\n    it('should return different id on lib change', function () {\n        assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, lib: 'llvm', protocolVersion: 3 }), '4bd647bcab41dd4b40022af2c88a86e0529611b0');\n    });\n})\n"
  },
  {
    "path": "test/options.test.js",
    "content": "﻿import * as libquick from '../src/libquick.js';\n\nimport assert from 'assert';\n\nconst startCode = `static void BM_StringCreation(benchmark::State& state) {\n  while (state.KeepRunning())\n    std::string empty_string;\n}\n// Register the function as a benchmark\nBENCHMARK(BM_StringCreation);\n\nstatic void BM_StringCopy(benchmark::State& state) {\n  std::string x = \"hello\";\n  while (state.KeepRunning())\n    std::string copy(x);\n}\nBENCHMARK(BM_StringCopy);\n`;\n\nconst request = {\n    code: startCode,\n    options: {\n        compiler: 'clang-5.0',\n        optim: 3,\n        cppVersion: 17,\n        lib: 'llvm',\n        flags: ['-ftesting']\n    },\n    disassemblyOption: \"att\",\n    protocolVersion: 5\n};\n\ndescribe('Save options', function () {\n    const firstName = libquick.makeName(request);\n    const saved = libquick.optionsToString(request);\n    let loaded = {};\n    loaded.options = JSON.parse(saved);\n    loaded.code = startCode;\n    const built = libquick.makeRequest(loaded);\n\n    it('should save enough to reload the request', function () {\n        assert.equal(libquick.makeName(built), firstName);\n    });\n});\n"
  },
  {
    "path": "test/test.func",
    "content": "BM_StringCreation\nBM_StringCopy"
  },
  {
    "path": "test/url-name.test.js",
    "content": "﻿import * as tools from '../src/tools.js';\nimport sha1 from 'sha1';\n\nimport assert from 'assert';\n\nconst refId = '630d398cbd8e8c9d76bd3fb17ede3b77abe4302e';\nconst refUrl = 'Yw05jL2OjJ12vT_xft47d6vkMC4';\nconst twoSlashes = 'hbkmjh-0uSQKrYlQ-qNjLpgDEto';\nconst twoSlashedId = '85b9268e1ff4b9240aad8950fea3632e980312da';\nconst twoPluses = 'hbkmjh_0uSQKrYlQ_qNjLpgDEto';\nconst twoPlusesId = '85b9268e1fb4b9240aad8950faa3632e980312da';\n\ndescribe('default codes', function () {\n    it('should return a stable encoding', function () {\n        assert.equal(tools.encodeName(refId), refUrl);\n    });\n    it('should return a stable decoding', function () {\n        assert.equal(tools.decodeName(refUrl), refId);\n    });\n})\n\ndescribe('bijective', function () {\n    it('should be bijective', function () {\n        const name = sha1('Hello World!');\n        assert.equal(tools.decodeName(tools.encodeName(name)), name);\n    });\n})\n\ndescribe('URL safe', function () {\n    it('should give URL safe names', function () {\n        [...Array(10).keys()].map((val) => tools.encodeName(sha1(val))).forEach((val) => assert.equal(val, encodeURIComponent(val)));\n    });\n    it('should escape multiple slashes', function () {\n        assert.equal(tools.decodeName(twoSlashes), twoSlashedId);\n        assert.equal(tools.encodeName(twoSlashedId), twoSlashes);\n    })\n    it('should escape multiple plusses', function () {\n        assert.equal(tools.decodeName(twoPluses), twoPlusesId);\n        assert.equal(tools.encodeName(twoPlusesId), twoPluses);\n    })\n})\n"
  }
]