<commit_before>#!/usr/bin/env node

// NOTE: Don't require anything from node_modules here, since the
// install script has to be able to run _before_ that exists.
let child = require("child_process"), fs = require("fs"), path = require("path")

const {join} = path

let main = ["model", "transform", "state", "view",
            "keymap", "inputrules", "history", "collab", "commands", "gapcursor",
            "schema-basic", "schema-list"]
let mods = main.concat(["menu", "example-setup", "markdown", "dropcursor", "test-builder", "changeset"])
let modsAndWebsite = mods.concat("website")

let projectDir = join(__dirname, "..")

function joinP(...args) {
  return join(projectDir, ...args)
}

function mainFile(pkg) {
  let index = joinP(pkg, "src", "index.ts"), self = joinP(pkg, "src", pkg + ".ts")
  if (fs.existsSync(index)) return index
  if (fs.existsSync(self)) return self
  throw new Error("Couldn't find a main file for " + pkg)
}

function start() {
  let command = process.argv[2]
  if (command && !["install", "--help"].includes(command)) assertInstalled()
  let args = process.argv.slice(3)
  let cmdFn = {
    "status": status,
    "commit": commit,
    "install": install,
    "build": build,
    "test": test,
    "push": push,
    "pull": pull,
    "grep": grep,
    "run": runCmd,
    "watch": watch,
    "changes": changes,
    "modules": listModules,
    "release": release,
    "dev-start": devStart,
    "dev-stop": devStop,
    "mass-change": massChange,
    "--help": showHelp
  }[command]
  if (!cmdFn || cmdFn.length > args.length) help(1)
  cmdFn.apply(null, args)
}

function showHelp() {
  help(0)
}

function help(status) {
  console.log(`Usage:
  pm install [--ssh]      Clone and symlink the packages, install dependencies, build
  pm build                Build all modules
  pm status               Print out the git status of packages
  pm commit <args>        Run git commit in all packages that have changes
  pm push                 Run git push in packages that have new commits
  pm pull                 Run git pull in all packages
  pm test                 Run the tests from all packages
  pm watch                Set up a process that rebuilds the packages on change
  pm grep <pattern>       Grep through the source code for all packages
  pm run <command>        Run the given command in each of the package dirs
  pm changes              Show commits since the last release for all packages
  pm mass-change <files> <pattern> <replacement>
                          Run a regexp-replace on the matching files in each package
  pm release <module>     Generate a new release for the given module.
  pm modules [--core]     Emit a list of all package names
  pm dev-start            Start development server
  pm dev-stop             Stop development server, if running
  pm --help`)
  process.exit(status)
}

function assertInstalled() {
  modsAndWebsite.forEach(repo => {
    if (!fs.existsSync(joinP(repo))) {
      console.error("module `%s` is missing. Did you forget to run `pm install`?", repo)
      process.exit(1)
    }
  })
}

function run(cmd, args, pkg) {
  return child.execFileSync(cmd, args, {
    cwd: pkg === null ? undefined : pkg ? joinP(pkg) : projectDir,
    encoding: "utf8",
    stdio: ["ignore", "pipe", process.stderr]
  })
}

function status() {
  modsAndWebsite.forEach(repo => {
    let output = run("git", ["status", "-sb"], repo)
    if (output != "## master...origin/master\n")
      console.log(repo + ":\n" + run("git", ["status"], repo))
  })
}

function commit(...args) {
  modsAndWebsite.forEach(repo => {
    if (run("git", ["diff"], repo) || run("git", ["diff", "--cached"], repo))
      console.log(repo + ":\n" + run("git", ["commit"].concat(args), repo))
  })
}

function install(arg = null) {
  let base = "https://github.com/prosemirror/"
  if (arg == "--ssh") { base = "git@github.com:ProseMirror/" }
  else if (arg != null) help(1)

  modsAndWebsite.forEach(repo => {
    if (fs.existsSync(joinP(repo))) {
      console.warn("Skipping cloning of " + repo + " (directory exists)")
      return
    }
    let origin = base + (repo == "website" ? "" : "prosemirror-") + repo + ".git"
    run("git", ["clone", origin, repo])
  })

  console.log("Running npm install")
  run("npm", ["install"])
  console.log("Building modules")
  build()
}

async function build() {
  console.info("Building...")
  let t0 = Date.now()
  await require("@marijn/buildtool").build(mods.map(mainFile), buildOptions)
  console.info(`Done in ${((Date.now() - t0) / 1000).toFixed(2)}s`)
}

function test(...args) {
  let runTests = require("@marijn/testtool")
  let {tests, browserTests} = runTests.gatherTests(mods.map(m => joinP(m)))
  let browsers = [], grep, noBrowser = false
  for (let i = 0; i < args.length; i++) {
    if (args[i] == "--firefox") browsers.push("firefox")
    if (args[i] == "--chrome") browser.push("chrome")
    if (args[i] == "--no-browser") noBrowser = true
    if (args[i] == "--grep") grep = args[++i]
  }
  if (!browsers.length && !noBrowser) browsers.push("chrome")
  runTests.runTests({tests, browserTests, browsers, grep}).then(failed => process.exit(failed ? 1 : 0))
}

function push() {
  modsAndWebsite.forEach(repo => {
    if (/\bahead\b/.test(run("git", ["status", "-sb"], repo)))
      run("git", ["push"], repo)
  })
}

function pull() {
  modsAndWebsite.forEach(repo => run("git", ["pull"], repo))
}

function grep(pattern) {
  let files = []
  let glob = require("glob")
  mods.forEach(repo => {
    files = files.concat(glob.sync(joinP(repo, "src", "*.ts"))).concat(glob.sync(joinP(repo, "test", "*.ts")))
  })
  files = files.concat(glob.sync(joinP("website", "src", "**", "*.js")))
    .concat(glob.sync(joinP("website", "pages", "examples", "*", "*.js")))
  try {
    console.log(run("grep", ["--color", "-nH", "-e", pattern].concat(files.map(f => path.relative(process.cwd(), f))), null))
  } catch(e) {
    process.exit(1)
  }
}

function runCmd(cmd, ...args) {
  mods.forEach(repo => {
    console.log(repo + ":")
    try {
      console.log(run(cmd, args, repo))
    } catch (e) {
      console.log(e.toString())
      process.exit(1)
    }
  })
}

function changes() {
  mods.forEach(repo => {
    let lastTag = run("git", ["describe", "master", "--tags", "--abbrev=0"], repo).trim()
    if (!lastTag) return console.log("No previous tag for " + repo + "\n")
    let history = run("git", ["log", lastTag + "..master"], repo).trim()
    if (history) console.log(repo + ":\n" + "=".repeat(repo.length + 1) + "\n\n" + history + "\n")
  })
}

function editReleaseNotes(notes) {
  let noteFile = join(projectDir, "notes.txt")
  fs.writeFileSync(noteFile, notes.head + notes.body)
  run(process.env.EDITOR || "emacs", [noteFile], null)
  let edited = fs.readFileSync(noteFile)
  fs.unlinkSync(noteFile)
  if (!/\S/.test(edited)) process.exit(0)
  let split = /^(.*)\n+([^]*)/.exec(edited)
  return {head: split[1] + "\n\n", body: split[2]}
}

function release(mod, ...args) {
  let currentVersion = require(join("..", mod, "package.json")).version
  let changes = changelog(mod, currentVersion)
  let newVersion = bumpVersion(currentVersion, changes)
  console.log(`Creating prosemirror-${mod} ${newVersion}`)

  let notes = releaseNotes(mod, changes, newVersion)
  if (args.indexOf("--edit") > -1) nodes = editReleaseNotes(notes)

  setModuleVersion(mod, newVersion)
  if (changes.breaking.length) setDepVersion(mod, newVersion)
  fs.writeFileSync(joinP(mod, "CHANGELOG.md"), notes.head + notes.body + fs.readFileSync(joinP(mod, "CHANGELOG.md"), "utf8"))
  run("git", ["add", "package.json"], mod)
  run("git", ["add", "CHANGELOG.md"], mod)
  run("git", ["commit", "-m", `Mark version ${newVersion}`], mod)
  run("git", ["tag", newVersion, "-m", `Version ${newVersion}\n\n${notes.body}`, "--cleanup=verbatim"], mod)
}

function changelog(repo, since) {
  let commits = run("git", ["log", "--format=%B", "--reverse", since + "..master"], repo)
  let result = {fix: [], feature: [], breaking: []}
  let re = /\n\r?\n(BREAKING|FIX|FEATURE):\s*([^]*?)(?=\r?\n\r?\n|\r?\n?$)/g, match
  while (match = re.exec(commits)) result[match[1].toLowerCase()].push(match[2].replace(/\r?\n/g, " "))
  return result
}

function bumpVersion(version, changes) {
  let [major, minor, patch] = version.split(".")
  if (changes.breaking.length) return `${Number(major) + 1}.0.0`
  if (changes.feature.length) return `${major}.${Number(minor) + 1}.0`
  if (changes.fix.length) return `${major}.${minor}.${Number(patch) + 1}`
  throw new Error("No new release notes!")
}

function releaseNotes(mod, changes, version) {
  let pad = n => n < 10 ? "0" + n : n
  let d = new Date, date = d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate())

  let types = {breaking: "Breaking changes", fix: "Bug fixes", feature: "New features"}

  let refTarget = "https://prosemirror.net/docs/ref/"
  let head = `## ${version} (${date})\n\n`, body = ""
  for (let type in types) {
    let messages = changes[type]
    if (messages.length) body += `### ${types[type]}\n\n`
    messages.forEach(message => body += message.replace(/\]\(##/g, "](" + refTarget + "#") + "\n\n")
  }
  return {head, body}
}

function setModuleVersion(mod, version) {
  let file = joinP(mod, "package.json")
  fs.writeFileSync(file, fs.readFileSync(file, "utf8").replace(/"version":\s*".*?"/, `"version": "${version}"`))
}

function setDepVersion(mod, version) {
  modsAndWebsite.forEach(repo => {
    if (repo == mod) return
    let file = joinP(repo, "package.json"), text = fs.readFileSync(file, "utf8")
    let result = text.replace(/"prosemirror-(.*?)":\s*".*?"/g, (match, dep) => {
      return dep == mod ? `"prosemirror-${mod}": "^${version}"` : match
    })
    if (result != text) {
      fs.writeFileSync(file, result)
      run("git", ["add", "package.json"], repo)
      run("git", ["commit", "-m", `Upgrade prosemirror-${mod} dependency`], repo)
    }
  })
}

function listModules() {
  console.log((process.argv.includes("--core") ? main : mods).join("\n"))
}

const buildOptions = {
  tsOptions: {allowSyntheticDefaultImports: true}
}

function watch() {
  require("@marijn/buildtool").watch(mods.map(mainFile), [join(__dirname, "..", "demo", "demo.ts")], buildOptions)
}

const pidFile = join(__dirname, ".pm-dev.pid")
function devPID() {
  try { return JSON.parse(fs.readFileSync(pidFile, "utf8")) }
  catch(_) { return null }
}

function startServer() {
  let serve = path.resolve(join(__dirname, "..", "demo"))
  let port = +(process.env.PORT || 8080)
  let moduleserver = new (require("esmoduleserve/moduleserver"))({root: serve, maxDepth: 2})
  let serveStatic = require("serve-static")(serve)
  require("http").createServer((req, resp) => {
    if (/^\/test\/?($|\?)/.test(req.url)) {
      let runTests = require("@codemirror/buildhelper/src/runtests")
      let {browserTests} = runTests.gatherTests(mods.map(m => joinP(m)))
      resp.writeHead(200, {"content-type": "text/html"})
      resp.end(runTests.testHTML(browserTests.map(f => path.relative(serve, f)), false))
    } else {
      moduleserver.handleRequest(req, resp) || serveStatic(req, resp, _err => {
        resp.statusCode = 404
        resp.end('Not found')
      })
    }
  }).listen(port, process.env.OPEN ? undefined : "127.0.0.1")
  console.log(`Dev server listening on ${port}`)
}

function devStart() {
  let pid = devPID()
  if (pid != null) {
    try { run("ps", ["-p", String(pid)]) }
    catch (_) { pid = null }
  }
  if (pid != null) {
    console.log("Dev server already running at pid " + pid)
    return
  }

  fs.writeFileSync(pidFile, process.pid + "\n")
  function del() { fs.unlink(pidFile, () => {}); console.log("Stop") }
  function delAndExit() { del(); process.exit() }
  process.on("exit", del)
  process.on("SIGINT", delAndExit)
  process.on("SIGTERM", delAndExit)

  startServer()
  watch()
}

function devStop() {
  let pid = devPID()
  if (pid == null) {
    console.log("Dev server not running")
  } else {
    process.kill(pid, "SIGTERM")
    console.log("Killed dev server with pid " + pid)
  }
}

function massChange(file, pattern, replacement = "") {
  let re = new RegExp(pattern, "g")
  modsAndWebsite.forEach(repo => {
    let glob = require("glob")
    glob.sync(joinP(repo, file)).forEach(file => {
      let content = fs.readFileSync(file, "utf8"), changed = content.replace(re, replacement)
      if (changed != content) {
        console.log("Updated " + file)
        fs.writeFileSync(file, changed)
      }
    })
  })
}

start()
<commit_msg>Don't assert installed on 'pm modules' command<commit_after>#!/usr/bin/env node

// NOTE: Don't require anything from node_modules here, since the
// install script has to be able to run _before_ that exists.
let child = require("child_process"), fs = require("fs"), path = require("path")

const {join} = path

let main = ["model", "transform", "state", "view",
            "keymap", "inputrules", "history", "collab", "commands", "gapcursor",
            "schema-basic", "schema-list"]
let mods = main.concat(["menu", "example-setup", "markdown", "dropcursor", "test-builder", "changeset"])
let modsAndWebsite = mods.concat("website")

let projectDir = join(__dirname, "..")

function joinP(...args) {
  return join(projectDir, ...args)
}

function mainFile(pkg) {
  let index = joinP(pkg, "src", "index.ts"), self = joinP(pkg, "src", pkg + ".ts")
  if (fs.existsSync(index)) return index
  if (fs.existsSync(self)) return self
  throw new Error("Couldn't find a main file for " + pkg)
}

function start() {
  let command = process.argv[2]
  if (command && !["install", "--help", "modules"].includes(command)) assertInstalled()
  let args = process.argv.slice(3)
  let cmdFn = {
    "status": status,
    "commit": commit,
    "install": install,
    "build": build,
    "test": test,
    "push": push,
    "pull": pull,
    "grep": grep,
    "run": runCmd,
    "watch": watch,
    "changes": changes,
    "modules": listModules,
    "release": release,
    "dev-start": devStart,
    "dev-stop": devStop,
    "mass-change": massChange,
    "--help": showHelp
  }[command]
  if (!cmdFn || cmdFn.length > args.length) help(1)
  cmdFn.apply(null, args)
}

function showHelp() {
  help(0)
}

function help(status) {
  console.log(`Usage:
  pm install [--ssh]      Clone and symlink the packages, install dependencies, build
  pm build                Build all modules
  pm status               Print out the git status of packages
  pm commit <args>        Run git commit in all packages that have changes
  pm push                 Run git push in packages that have new commits
  pm pull                 Run git pull in all packages
  pm test                 Run the tests from all packages
  pm watch                Set up a process that rebuilds the packages on change
  pm grep <pattern>       Grep through the source code for all packages
  pm run <command>        Run the given command in each of the package dirs
  pm changes              Show commits since the last release for all packages
  pm mass-change <files> <pattern> <replacement>
                          Run a regexp-replace on the matching files in each package
  pm release <module>     Generate a new release for the given module.
  pm modules [--core]     Emit a list of all package names
  pm dev-start            Start development server
  pm dev-stop             Stop development server, if running
  pm --help`)
  process.exit(status)
}

function assertInstalled() {
  modsAndWebsite.forEach(repo => {
    if (!fs.existsSync(joinP(repo))) {
      console.error("module `%s` is missing. Did you forget to run `pm install`?", repo)
      process.exit(1)
    }
  })
}

function run(cmd, args, pkg) {
  return child.execFileSync(cmd, args, {
    cwd: pkg === null ? undefined : pkg ? joinP(pkg) : projectDir,
    encoding: "utf8",
    stdio: ["ignore", "pipe", process.stderr]
  })
}

function status() {
  modsAndWebsite.forEach(repo => {
    let output = run("git", ["status", "-sb"], repo)
    if (output != "## master...origin/master\n")
      console.log(repo + ":\n" + run("git", ["status"], repo))
  })
}

function commit(...args) {
  modsAndWebsite.forEach(repo => {
    if (run("git", ["diff"], repo) || run("git", ["diff", "--cached"], repo))
      console.log(repo + ":\n" + run("git", ["commit"].concat(args), repo))
  })
}

function install(arg = null) {
  let base = "https://github.com/prosemirror/"
  if (arg == "--ssh") { base = "git@github.com:ProseMirror/" }
  else if (arg != null) help(1)

  modsAndWebsite.forEach(repo => {
    if (fs.existsSync(joinP(repo))) {
      console.warn("Skipping cloning of " + repo + " (directory exists)")
      return
    }
    let origin = base + (repo == "website" ? "" : "prosemirror-") + repo + ".git"
    run("git", ["clone", origin, repo])
  })

  console.log("Running npm install")
  run("npm", ["install"])
  console.log("Building modules")
  build()
}

async function build() {
  console.info("Building...")
  let t0 = Date.now()
  await require("@marijn/buildtool").build(mods.map(mainFile), buildOptions)
  console.info(`Done in ${((Date.now() - t0) / 1000).toFixed(2)}s`)
}

function test(...args) {
  let runTests = require("@marijn/testtool")
  let {tests, browserTests} = runTests.gatherTests(mods.map(m => joinP(m)))
  let browsers = [], grep, noBrowser = false
  for (let i = 0; i < args.length; i++) {
    if (args[i] == "--firefox") browsers.push("firefox")
    if (args[i] == "--chrome") browser.push("chrome")
    if (args[i] == "--no-browser") noBrowser = true
    if (args[i] == "--grep") grep = args[++i]
  }
  if (!browsers.length && !noBrowser) browsers.push("chrome")
  runTests.runTests({tests, browserTests, browsers, grep}).then(failed => process.exit(failed ? 1 : 0))
}

function push() {
  modsAndWebsite.forEach(repo => {
    if (/\bahead\b/.test(run("git", ["status", "-sb"], repo)))
      run("git", ["push"], repo)
  })
}

function pull() {
  modsAndWebsite.forEach(repo => run("git", ["pull"], repo))
}

function grep(pattern) {
  let files = []
  let glob = require("glob")
  mods.forEach(repo => {
    files = files.concat(glob.sync(joinP(repo, "src", "*.ts"))).concat(glob.sync(joinP(repo, "test", "*.ts")))
  })
  files = files.concat(glob.sync(joinP("website", "src", "**", "*.js")))
    .concat(glob.sync(joinP("website", "pages", "examples", "*", "*.js")))
  try {
    console.log(run("grep", ["--color", "-nH", "-e", pattern].concat(files.map(f => path.relative(process.cwd(), f))), null))
  } catch(e) {
    process.exit(1)
  }
}

function runCmd(cmd, ...args) {
  mods.forEach(repo => {
    console.log(repo + ":")
    try {
      console.log(run(cmd, args, repo))
    } catch (e) {
      console.log(e.toString())
      process.exit(1)
    }
  })
}

function changes() {
  mods.forEach(repo => {
    let lastTag = run("git", ["describe", "master", "--tags", "--abbrev=0"], repo).trim()
    if (!lastTag) return console.log("No previous tag for " + repo + "\n")
    let history = run("git", ["log", lastTag + "..master"], repo).trim()
    if (history) console.log(repo + ":\n" + "=".repeat(repo.length + 1) + "\n\n" + history + "\n")
  })
}

function editReleaseNotes(notes) {
  let noteFile = join(projectDir, "notes.txt")
  fs.writeFileSync(noteFile, notes.head + notes.body)
  run(process.env.EDITOR || "emacs", [noteFile], null)
  let edited = fs.readFileSync(noteFile)
  fs.unlinkSync(noteFile)
  if (!/\S/.test(edited)) process.exit(0)
  let split = /^(.*)\n+([^]*)/.exec(edited)
  return {head: split[1] + "\n\n", body: split[2]}
}

function release(mod, ...args) {
  let currentVersion = require(join("..", mod, "package.json")).version
  let changes = changelog(mod, currentVersion)
  let newVersion = bumpVersion(currentVersion, changes)
  console.log(`Creating prosemirror-${mod} ${newVersion}`)

  let notes = releaseNotes(mod, changes, newVersion)
  if (args.indexOf("--edit") > -1) nodes = editReleaseNotes(notes)

  setModuleVersion(mod, newVersion)
  if (changes.breaking.length) setDepVersion(mod, newVersion)
  fs.writeFileSync(joinP(mod, "CHANGELOG.md"), notes.head + notes.body + fs.readFileSync(joinP(mod, "CHANGELOG.md"), "utf8"))
  run("git", ["add", "package.json"], mod)
  run("git", ["add", "CHANGELOG.md"], mod)
  run("git", ["commit", "-m", `Mark version ${newVersion}`], mod)
  run("git", ["tag", newVersion, "-m", `Version ${newVersion}\n\n${notes.body}`, "--cleanup=verbatim"], mod)
}

function changelog(repo, since) {
  let commits = run("git", ["log", "--format=%B", "--reverse", since + "..master"], repo)
  let result = {fix: [], feature: [], breaking: []}
  let re = /\n\r?\n(BREAKING|FIX|FEATURE):\s*([^]*?)(?=\r?\n\r?\n|\r?\n?$)/g, match
  while (match = re.exec(commits)) result[match[1].toLowerCase()].push(match[2].replace(/\r?\n/g, " "))
  return result
}

function bumpVersion(version, changes) {
  let [major, minor, patch] = version.split(".")
  if (changes.breaking.length) return `${Number(major) + 1}.0.0`
  if (changes.feature.length) return `${major}.${Number(minor) + 1}.0`
  if (changes.fix.length) return `${major}.${minor}.${Number(patch) + 1}`
  throw new Error("No new release notes!")
}

function releaseNotes(mod, changes, version) {
  let pad = n => n < 10 ? "0" + n : n
  let d = new Date, date = d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate())

  let types = {breaking: "Breaking changes", fix: "Bug fixes", feature: "New features"}

  let refTarget = "https://prosemirror.net/docs/ref/"
  let head = `## ${version} (${date})\n\n`, body = ""
  for (let type in types) {
    let messages = changes[type]
    if (messages.length) body += `### ${types[type]}\n\n`
    messages.forEach(message => body += message.replace(/\]\(##/g, "](" + refTarget + "#") + "\n\n")
  }
  return {head, body}
}

function setModuleVersion(mod, version) {
  let file = joinP(mod, "package.json")
  fs.writeFileSync(file, fs.readFileSync(file, "utf8").replace(/"version":\s*".*?"/, `"version": "${version}"`))
}

function setDepVersion(mod, version) {
  modsAndWebsite.forEach(repo => {
    if (repo == mod) return
    let file = joinP(repo, "package.json"), text = fs.readFileSync(file, "utf8")
    let result = text.replace(/"prosemirror-(.*?)":\s*".*?"/g, (match, dep) => {
      return dep == mod ? `"prosemirror-${mod}": "^${version}"` : match
    })
    if (result != text) {
      fs.writeFileSync(file, result)
      run("git", ["add", "package.json"], repo)
      run("git", ["commit", "-m", `Upgrade prosemirror-${mod} dependency`], repo)
    }
  })
}

function listModules() {
  console.log((process.argv.includes("--core") ? main : mods).join("\n"))
}

const buildOptions = {
  tsOptions: {allowSyntheticDefaultImports: true}
}

function watch() {
  require("@marijn/buildtool").watch(mods.map(mainFile), [join(__dirname, "..", "demo", "demo.ts")], buildOptions)
}

const pidFile = join(__dirname, ".pm-dev.pid")
function devPID() {
  try { return JSON.parse(fs.readFileSync(pidFile, "utf8")) }
  catch(_) { return null }
}

function startServer() {
  let serve = path.resolve(join(__dirname, "..", "demo"))
  let port = +(process.env.PORT || 8080)
  let moduleserver = new (require("esmoduleserve/moduleserver"))({root: serve, maxDepth: 2})
  let serveStatic = require("serve-static")(serve)
  require("http").createServer((req, resp) => {
    if (/^\/test\/?($|\?)/.test(req.url)) {
      let runTests = require("@codemirror/buildhelper/src/runtests")
      let {browserTests} = runTests.gatherTests(mods.map(m => joinP(m)))
      resp.writeHead(200, {"content-type": "text/html"})
      resp.end(runTests.testHTML(browserTests.map(f => path.relative(serve, f)), false))
    } else {
      moduleserver.handleRequest(req, resp) || serveStatic(req, resp, _err => {
        resp.statusCode = 404
        resp.end('Not found')
      })
    }
  }).listen(port, process.env.OPEN ? undefined : "127.0.0.1")
  console.log(`Dev server listening on ${port}`)
}

function devStart() {
  let pid = devPID()
  if (pid != null) {
    try { run("ps", ["-p", String(pid)]) }
    catch (_) { pid = null }
  }
  if (pid != null) {
    console.log("Dev server already running at pid " + pid)
    return
  }

  fs.writeFileSync(pidFile, process.pid + "\n")
  function del() { fs.unlink(pidFile, () => {}); console.log("Stop") }
  function delAndExit() { del(); process.exit() }
  process.on("exit", del)
  process.on("SIGINT", delAndExit)
  process.on("SIGTERM", delAndExit)

  startServer()
  watch()
}

function devStop() {
  let pid = devPID()
  if (pid == null) {
    console.log("Dev server not running")
  } else {
    process.kill(pid, "SIGTERM")
    console.log("Killed dev server with pid " + pid)
  }
}

function massChange(file, pattern, replacement = "") {
  let re = new RegExp(pattern, "g")
  modsAndWebsite.forEach(repo => {
    let glob = require("glob")
    glob.sync(joinP(repo, file)).forEach(file => {
      let content = fs.readFileSync(file, "utf8"), changed = content.replace(re, replacement)
      if (changed != content) {
        console.log("Updated " + file)
        fs.writeFileSync(file, changed)
      }
    })
  })
}

start()
<|endoftext|>


<commit_before>/*
Script: MooEditable.UI.Forecolor.js
	Extends MooEditable to change the color of the text from a list a predefined colors.

Usage:
   Add the following tags in your html
   <link rel="stylesheet" type="text/css" href="MooEditable.Forecolor.css">

License:
	MIT-style license.

Author:
    Olivier Refalo orefalo@yahoo.com
*/

MooEditable.Actions.forecolor = {
	type: 'button-overlay',
	title: 'Change Color',
	options: {
		overlaySize: {x: 'auto'},
		overlayHTML: (function(){
			var html = '';
			var colors = [
				['000000', '993300', '333300', '003300', '003366', '000077', '333399', '333333'],
				['770000', 'ff6600', '777700', '007700', '007777', '0000ff', '666699', '777777'],
				['ff0000', 'ff9900', '99cc00', '339966', '33cccc', '3366f0', '770077', '999999'],
				['ff00ff', 'ffcc00', 'ffff00', '00ff00', '00ffff', '00ccff', '993366', 'cccccc'],
				['ff99cc', 'ffcc99', 'ffff99', 'ccffcc', 'ccffff', '99ccff', 'cc9977', 'ffffff']
			];
			$each(colors, function(row){
				$each(row, function(c){
					html += '';
				});
				html += '';
			});
			return html;
		})()
	},
	command: function(buttonOverlay, e){
		var el = e.target;
		if (el.tagName.toLowerCase() != 'a') return;
		var color = $(el).getStyle('background-color');
		this.execute('forecolor', false, color);
		this.focus();
	}
};

<commit_msg>use Array.each<commit_after>/*
Script: MooEditable.UI.Forecolor.js
	Extends MooEditable to change the color of the text from a list a predefined colors.

Usage:
   Add the following tags in your html
   <link rel="stylesheet" type="text/css" href="MooEditable.Forecolor.css">

License:
	MIT-style license.

Author:
    Olivier Refalo orefalo@yahoo.com
*/

MooEditable.Actions.forecolor = {
	type: 'button-overlay',
	title: 'Change Color',
	options: {
		overlaySize: {x: 'auto'},
		overlayHTML: (function(){
			var colors = [
				['000000', '993300', '333300', '003300', '003366', '000077', '333399', '333333'],
				['770000', 'ff6600', '777700', '007700', '007777', '0000ff', '666699', '777777'],
				['ff0000', 'ff9900', '99cc00', '339966', '33cccc', '3366f0', '770077', '999999'],
				['ff00ff', 'ffcc00', 'ffff00', '00ff00', '00ffff', '00ccff', '993366', 'cccccc'],
				['ff99cc', 'ffcc99', 'ffff99', 'ccffcc', 'ccffff', '99ccff', 'cc9977', 'ffffff']
			];
			var html = '';
			colors.each(function(row){
				row.each(function(c){
					html += '';
				});
				html += '';
			});
			return html;
		})()
	},
	command: function(buttonOverlay, e){
		var el = e.target;
		if (el.tagName.toLowerCase() != 'a') return;
		var color = $(el).getStyle('background-color');
		this.execute('forecolor', false, color);
		this.focus();
	}
};

<|endoftext|>


<commit_before>'use strict';

const escape = require('escape-html');
const handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');

// generate the html report and return it as a string
module.exports = function generateHtmlReport(reportData) {

  return new Promise((resolve, reject) => {
    var flatListOfViolations = createFlatListOfViolations(reportData.assertions);
    var violationStats = collectViolationStats(flatListOfViolations);
    var violationFilters = createViolationFilters(flatListOfViolations);
    var rulesetTagLabels = {
      'wcag2a': 'WCAG 2.0 A',
      'wcag2aa': 'WCAG 2.0 AA',
      'EPUB': 'EPUB',
      'best-practice': 'Best Practice',
      'other': 'Other'
    };

    // return 5 data cells for each ruleset: critical, serious, moderate, minor, total
    // a ruleset can be "wcag2a", "wcag2aa", "EPUB", "other", or "total" (all rulesets)
    handlebars.registerHelper('violation_stats', function(rule, options) {
      var str = "" + violationStats[rule]['critical'] + "	"
                + "" + violationStats[rule]['serious'] + "	"
                + "" + violationStats[rule]['moderate'] + "	"
                + "" + violationStats[rule]['minor'] + "	"
                + "" + violationStats[rule]['total'] + "	"
      return new handlebars.SafeString(str);
    });

    // return a list of <option> elements containing the possible filters for given rule
    handlebars.registerHelper('violation_filter', function(rule, options) {
      var filterOptions = "";
      violationFilters[rule].forEach(function(value) {
        // use nicer labels for ruleset options
        if (rule == "ruleset") {
          filterOptions += "<option value='" + value + "'>" + rulesetTagLabels[value] + "</option>";
        }
        else {
          filterOptions += "<option value='" + value + "'>" + value + "</option>";
        }
      });
      return new handlebars.SafeString(filterOptions);
    });

    // return a stringified json object representing a flat list of violations
    handlebars.registerHelper('violationsJson', function(options) {
      return new handlebars.SafeString(JSON.stringify(flatListOfViolations) + ";")
    });

    handlebars.registerHelper('violationRows', function(options) {
      var htmlStr = '';
      flatListOfViolations.forEach(function(violation) {
        htmlStr += `

        ${violation['impact']}
        ${rulesetTagLabels[violation['applicableRulesetTag']]}
        \"${violation['fileTitle']}\"

${violation['location']}`;

        if (violation.html) {
          htmlStr +=`<br/><br/><div class='snippet'>Snippet:<code>${violation.html.trim()}</code></div>`;
        }

        htmlStr += "	";
        htmlStr += `<td>${violation['rule']}<br/><br/><span class='engine'>${violation['engine']}</span></td>`;

        var desc = violation["desc"];
        desc = desc.replace("Fix all of the following:", "");
        desc = desc.replace("Fix any of the following:", "");

        var detailsArr = desc.split("\n");
        var listStr = '';
        detailsArr.forEach(function(item) {
          if (item != "") {
            listStr += `<li>${unescape(item)}</li>`;
          }
        });

        htmlStr += `

${listStr}

Learn more about ${violation['kbtitle']}

        	`;

        htmlStr += "
";
      });
      return new handlebars.SafeString(htmlStr);
    });

    const content = fs.readFileSync(path.join(__dirname, "./report-template.handlebars")).toString();
    var template = handlebars.compile(content);
    var result = template(reportData);
    resolve(result);
  });
};

// summarize the violation ruleset and impact data
function collectViolationStats(flatListOfViolations) {
  var rulesetTags = ['wcag2a', 'wcag2aa', 'EPUB', 'best-practice'];

  var summaryData = {
    'wcag2a': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'wcag2aa': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'EPUB': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'best-practice': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'other': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'total': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0}
  };

  flatListOfViolations.forEach(function(item) {
    var found = false;
    item.rulesetTags.forEach(function(tag) {
      if (rulesetTags.indexOf(tag) > -1) {
        summaryData[tag][item.impact] += 1;
        summaryData[tag]['total'] += 1;
        found = true;
      }
    });
    if (!found) {
      summaryData['other'][item.impact] += 1;
      summaryData['other']['total'] += 1;
    }
  });

  Object.keys(summaryData['total']).forEach(function(key) {
    summaryData['total'][key] += summaryData['wcag2a'][key]
      + summaryData['wcag2aa'][key]
      + summaryData['EPUB'][key]
      + summaryData['best-practice'][key]
      + summaryData['other'][key];
  });

  return summaryData;
}

// collect the valid values for each filter type
function createViolationFilters(violations) {
  var filters = {
      "rule": [],
      "ruleset": [],
      "impact": [],
      "file": []
  };

  violations.forEach(function(violation) {
    addIfUnique(violation["rule"], filters["rule"]);
    addIfUnique(violation["applicableRulesetTag"], filters["ruleset"]);
    addIfUnique(violation["impact"], filters["impact"]);
    addIfUnique(violation["file"], filters["file"]);
  });

  return filters;
}

// turn the nested assertions into a flat list of violations
// we're using 'assertion' and 'violation' somewhat interchangeably
function createFlatListOfViolations(violations) {
  var flatData = [];
  var rulesetTags = ['wcag2a', 'wcag2aa', 'EPUB', 'best-practice']; // applicable ruleset tags

  violations.forEach(function(assertion) {
    var filename = assertion["earl:testSubject"]["url"];
    var filetitle = assertion["earl:testSubject"]["dct:title"];
    assertion.assertions.forEach(function(item) {

      // each item may have multiple ruleset tags from the underlying html checker
      // narrow it down to one, from our list above, or label as 'other'
      var applicableRulesetTag = "other";
      item["earl:test"]["rulesetTags"].forEach(function(tag) {
        if (rulesetTags.indexOf(tag) != -1) {
          applicableRulesetTag = tag;
        }
      });

      var obj = {
        "file": filename,
        "filetitle": filetitle,
        "engine": item["earl:assertedBy"],
        "kburl": item["earl:test"]["help"]["url"],
        "kbtitle": item["earl:test"]["help"]["dct:title"],
        "rule": item["earl:test"]["dct:title"],
        "desc": escape(item["earl:result"]["dct:description"]),
        "pointer": item["earl:result"]["earl:pointer"],
        "impact": item["earl:test"]["earl:impact"],
        "location": filename,
        "rulesetTags": item["earl:test"]["rulesetTags"],
        "applicableRulesetTag": applicableRulesetTag
      };
      if (item["earl:result"]["earl:pointer"]) {
        obj.location += "#epubcfi(" + item["earl:result"]["earl:pointer"]["cfi"] + ")";
      }
      if (item["earl:result"]["html"]) {
        obj.html = escape(item["earl:result"]["html"]);
      }
      flatData.push(obj);
    });
  });
  return flatData;
}

// utility function
function addIfUnique(value, list) {
  if (list.indexOf(value) == -1) {
    list.push(value);
  }
}
<commit_msg>fix(report): correct table column ordering<commit_after>'use strict';

const escape = require('escape-html');
const handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');

// generate the html report and return it as a string
module.exports = function generateHtmlReport(reportData) {

  return new Promise((resolve, reject) => {
    var flatListOfViolations = createFlatListOfViolations(reportData.assertions);
    var violationStats = collectViolationStats(flatListOfViolations);
    var violationFilters = createViolationFilters(flatListOfViolations);
    var rulesetTagLabels = {
      'wcag2a': 'WCAG 2.0 A',
      'wcag2aa': 'WCAG 2.0 AA',
      'EPUB': 'EPUB',
      'best-practice': 'Best Practice',
      'other': 'Other'
    };

    // return 5 data cells for each ruleset: critical, serious, moderate, minor, total
    // a ruleset can be "wcag2a", "wcag2aa", "EPUB", "other", or "total" (all rulesets)
    handlebars.registerHelper('violation_stats', function(rule, options) {
      var str = "" + violationStats[rule]['critical'] + "	"
                + "" + violationStats[rule]['serious'] + "	"
                + "" + violationStats[rule]['moderate'] + "	"
                + "" + violationStats[rule]['minor'] + "	"
                + "" + violationStats[rule]['total'] + "	"
      return new handlebars.SafeString(str);
    });

    // return a list of <option> elements containing the possible filters for given rule
    handlebars.registerHelper('violation_filter', function(rule, options) {
      var filterOptions = "";
      violationFilters[rule].forEach(function(value) {
        // use nicer labels for ruleset options
        if (rule == "ruleset") {
          filterOptions += "<option value='" + value + "'>" + rulesetTagLabels[value] + "</option>";
        }
        else {
          filterOptions += "<option value='" + value + "'>" + value + "</option>";
        }
      });
      return new handlebars.SafeString(filterOptions);
    });

    // return a stringified json object representing a flat list of violations
    handlebars.registerHelper('violationsJson', function(options) {
      return new handlebars.SafeString(JSON.stringify(flatListOfViolations) + ";")
    });

    handlebars.registerHelper('violationRows', function(options) {
      var htmlStr = '';
      flatListOfViolations.forEach(function(violation) {
        htmlStr += `

        ${violation['impact']}
        ${rulesetTagLabels[violation['applicableRulesetTag']]}
        ${violation['rule']}

${violation['engine']}
        \"${violation['fileTitle']}\"

${violation['location']}`;

        if (violation.html) {
          htmlStr +=`<br/><br/><div class='snippet'>Snippet:<code>${violation.html.trim()}</code></div>`;
        }

        htmlStr += "	";

        var desc = violation["desc"];
        desc = desc.replace("Fix all of the following:", "");
        desc = desc.replace("Fix any of the following:", "");

        var detailsArr = desc.split("\n");
        var listStr = '';
        detailsArr.forEach(function(item) {
          if (item != "") {
            listStr += `<li>${unescape(item)}</li>`;
          }
        });

        htmlStr += `

${listStr}

Learn more about ${violation['kbtitle']}

        	`;

        htmlStr += "
";
      });
      return new handlebars.SafeString(htmlStr);
    });

    const content = fs.readFileSync(path.join(__dirname, "./report-template.handlebars")).toString();
    var template = handlebars.compile(content);
    var result = template(reportData);
    resolve(result);
  });
};

// summarize the violation ruleset and impact data
function collectViolationStats(flatListOfViolations) {
  var rulesetTags = ['wcag2a', 'wcag2aa', 'EPUB', 'best-practice'];

  var summaryData = {
    'wcag2a': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'wcag2aa': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'EPUB': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'best-practice': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'other': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0},
    'total': {'critical': 0, 'serious': 0, 'moderate': 0, 'minor': 0, 'total': 0}
  };

  flatListOfViolations.forEach(function(item) {
    var found = false;
    item.rulesetTags.forEach(function(tag) {
      if (rulesetTags.indexOf(tag) > -1) {
        summaryData[tag][item.impact] += 1;
        summaryData[tag]['total'] += 1;
        found = true;
      }
    });
    if (!found) {
      summaryData['other'][item.impact] += 1;
      summaryData['other']['total'] += 1;
    }
  });

  Object.keys(summaryData['total']).forEach(function(key) {
    summaryData['total'][key] += summaryData['wcag2a'][key]
      + summaryData['wcag2aa'][key]
      + summaryData['EPUB'][key]
      + summaryData['best-practice'][key]
      + summaryData['other'][key];
  });

  return summaryData;
}

// collect the valid values for each filter type
function createViolationFilters(violations) {
  var filters = {
      "rule": [],
      "ruleset": [],
      "impact": [],
      "file": []
  };

  violations.forEach(function(violation) {
    addIfUnique(violation["rule"], filters["rule"]);
    addIfUnique(violation["applicableRulesetTag"], filters["ruleset"]);
    addIfUnique(violation["impact"], filters["impact"]);
    addIfUnique(violation["file"], filters["file"]);
  });

  return filters;
}

// turn the nested assertions into a flat list of violations
// we're using 'assertion' and 'violation' somewhat interchangeably
function createFlatListOfViolations(violations) {
  var flatData = [];
  var rulesetTags = ['wcag2a', 'wcag2aa', 'EPUB', 'best-practice']; // applicable ruleset tags

  violations.forEach(function(assertion) {
    var filename = assertion["earl:testSubject"]["url"];
    var filetitle = assertion["earl:testSubject"]["dct:title"];
    assertion.assertions.forEach(function(item) {

      // each item may have multiple ruleset tags from the underlying html checker
      // narrow it down to one, from our list above, or label as 'other'
      var applicableRulesetTag = "other";
      item["earl:test"]["rulesetTags"].forEach(function(tag) {
        if (rulesetTags.indexOf(tag) != -1) {
          applicableRulesetTag = tag;
        }
      });

      var obj = {
        "file": filename,
        "filetitle": filetitle,
        "engine": item["earl:assertedBy"],
        "kburl": item["earl:test"]["help"]["url"],
        "kbtitle": item["earl:test"]["help"]["dct:title"],
        "rule": item["earl:test"]["dct:title"],
        "desc": escape(item["earl:result"]["dct:description"]),
        "pointer": item["earl:result"]["earl:pointer"],
        "impact": item["earl:test"]["earl:impact"],
        "location": filename,
        "rulesetTags": item["earl:test"]["rulesetTags"],
        "applicableRulesetTag": applicableRulesetTag
      };
      if (item["earl:result"]["earl:pointer"]) {
        obj.location += "#epubcfi(" + item["earl:result"]["earl:pointer"]["cfi"] + ")";
      }
      if (item["earl:result"]["html"]) {
        obj.html = escape(item["earl:result"]["html"]);
      }
      flatData.push(obj);
    });
  });
  return flatData;
}

// utility function
function addIfUnique(value, list) {
  if (list.indexOf(value) == -1) {
    list.push(value);
  }
}
<|endoftext|>


<commit_before>/**
 * The App component is the component that is rendered around all views, and
 * contains common things like navigation, footer, etc.
 */

import React from 'react';

import MobileNavigation from './components/Navigation/Mobile';
import PrimaryNavigation from './components/Navigation/Primary';
import SecondaryNavigation from './components/Navigation/Secondary';
import Footer from './components/Footer';

const App = (props) => {
	const listsByPath = require('../utils/lists').listsByPath;
	// If we're on either a list or an item view
	let currentList, currentSection;
	if (props.params.listId) {
		currentList = listsByPath[props.params.listId];
		// Get the current section we're in for the navigation
		currentSection = Keystone.nav.by.list[currentList.key];
	}
	// Default current section key to dashboard
	const currentSectionKey = (currentSection && currentSection.key) || 'dashboard';
	return (

				<MobileNavigation
					brand={Keystone.brand}
					currentListKey={props.params.listId}
					currentSectionKey={currentSectionKey}
					sections={Keystone.nav.sections}
					signoutUrl={Keystone.signoutUrl}
				/>
				<PrimaryNavigation
					currentSectionKey={currentSectionKey}
					brand={Keystone.brand}
					sections={Keystone.nav.sections}
					signoutUrl={Keystone.signoutUrl}
				/>
				{/* If a section is open currently, show the secondary nav */}
				{(currentSection) ? (
					<SecondaryNavigation
						currentListKey={props.params.listId}
						lists={currentSection.lists}
						itemId={props.params.itemId}
					/>
				) : null}

				{props.children}

	);
};

module.exports = App;
<commit_msg>Display error when going to invalid list path<commit_after>/**
 * The App component is the component that is rendered around all views, and
 * contains common things like navigation, footer, etc.
 */

import React from 'react';
import { Container } from 'elemental';
import { Link } from 'react-router';

import MobileNavigation from './components/Navigation/Mobile';
import PrimaryNavigation from './components/Navigation/Primary';
import SecondaryNavigation from './components/Navigation/Secondary';
import Footer from './components/Footer';

const App = (props) => {
	const listsByPath = require('../utils/lists').listsByPath;
	let children = props.children;
	// If we're on either a list or an item view
	let currentList, currentSection;
	if (props.params.listId) {
		currentList = listsByPath[props.params.listId];
		// If we're on a list path that doesn't exist (e.g. /keystone/gibberishasfw34afsd) this will
		// be undefined
		if (!currentList) {
			children = (
				<Container>

List not found!

					<Link to={`${Keystone.adminPath}`}>
						Go back home
					</Link>
				</Container>
			);
		} else {
			// Get the current section we're in for the navigation
			currentSection = Keystone.nav.by.list[currentList.key];
		}
	}
	// Default current section key to dashboard
	const currentSectionKey = (currentSection && currentSection.key) || 'dashboard';
	return (

				<MobileNavigation
					brand={Keystone.brand}
					currentListKey={props.params.listId}
					currentSectionKey={currentSectionKey}
					sections={Keystone.nav.sections}
					signoutUrl={Keystone.signoutUrl}
				/>
				<PrimaryNavigation
					currentSectionKey={currentSectionKey}
					brand={Keystone.brand}
					sections={Keystone.nav.sections}
					signoutUrl={Keystone.signoutUrl}
				/>
				{/* If a section is open currently, show the secondary nav */}
				{(currentSection) ? (
					<SecondaryNavigation
						currentListKey={props.params.listId}
						lists={currentSection.lists}
						itemId={props.params.itemId}
					/>
				) : null}

				{children}

	);
};

module.exports = App;
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';

import './styles.css';

export default class FourOhFour extends PureComponent {
  render() {
    return
404: No love found
;
  }
}
<commit_msg>Show header in 404 page<commit_after>import React, { PureComponent, Fragment } from 'react';
import Header from '../Header';

import './styles.css';

export default class FourOhFour extends PureComponent {
  render() {
    return (
      <Fragment>

404: No love found

      </Fragment>
    );
  }
}
<|endoftext|>


<commit_before>import Debug from 'debug';
import errors from 'feathers-errors';

const debug = Debug('feathers-authentication:middleware');
const THIRTY_SECONDS = 30000;

// Usually this is a big no no but passport requires the
// request object to inspect req.body and req.query so we
// need to miss behave a bit. Don't do this in your own code!
export let exposeConnectMiddleware = function(req, res, next) {
  req.feathers.req = req;
  req.feathers.res = res;
  next();
};

// Make the authenticated passport user also available for REST services.
// We might need this for when we have session supported auth.
// export let exposeAuthenticatedUser = function(options = {}) {
//   return function(req, res, next) {
//     req.feathers.user = req.user;
//     next();
//   };
// };

// Make sure than an auth token passed in is available for hooks
// and services. This gracefully falls back from
// header -> cookie -> body -> query string
export let normalizeAuthToken = function(options = {}) {
  debug('Setting up normalizeAuthToken middleware with options:', options);

  if (!options.header) {
    throw new Error(`'header' must be provided to normalizeAuthToken() middleware`);
  }

  return function(req, res, next) {
    let token = req.headers[options.header];

    // Check the header for the token (preferred method)
    if (token) {
      // if the value contains "bearer" or "Bearer" then cut that part out
      if ( /bearer/i.test(token) ) {
        token = token.split(' ')[1];
      }
    }

    // Check the body next if we still don't have a token
    if (req.body.token) {
      token = req.body.token;
      delete req.body.token;
    }
    // Finally, check the query string. (worst method but nice for quick local dev)
    else if (req.query.token) {
      token = req.query.token;
      delete req.query.token;
    }

    // Tack it on to our feathers object so that it is passed to services
    req.feathers.token = token;

    next();
  };
};

export let successfulLogin = function(options = {}) {
  debug('Setting up successfulLogin middleware with options:', options);

  if (options.cookie === undefined) {
    throw new Error(`'cookie' must be provided to successfulLogin() middleware or set to 'false'`);
  }

  return function(req, res, next) {
    // NOTE (EK): If we are not dealing with a browser or it was an
    // XHR request then just skip this. This is primarily for
    // handling the oauth redirects and for us to securely send the
    // JWT to the client in a cookie.
    if (!options.successRedirect || req.xhr || req.is('json') || !req.accepts('html')) {
      return next();
    }

    // If cookies are enabled set our JWT in a cookie.
    if (options.cookie) {
      // clear any previous JWT cookie
      res.clearCookie(options.cookie.name);

      // Only send back cookies when not in production or when in production and using HTTPS
      if (!req.secure && process.env.NODE_ENV === 'production') {
        console.error(`You should be using HTTPS in production! Refusing to send JWT in a cookie`);
      }
      else {
        const cookieOptions = Object.assign({}, options.cookie, { path: options.successRedirect });

        // If a custom expiry wasn't passed then set the expiration to be 30 seconds from now.
        if (cookieOptions.expires === undefined) {
          const expiry = new Date();
          expiry.setTime(expiry.getTime() + THIRTY_SECONDS);
          cookieOptions.expires = expiry;
        }

        if ( !(cookieOptions.expires instanceof Date) ) {
          throw new Error('cookie.expires must be a valid Date object');
        }

        res.cookie(options.cookie.name, res.data.token, cookieOptions);
      }
    }

    // Redirect to our success route
    res.redirect(options.successRedirect);
  };
};

export let failedLogin = function(options = {}) {
  debug('Setting up failedLogin middleware with options:', options);

  if (options.cookie === undefined) {
    throw new Error(`'cookie' must be provided to failedLogin() middleware or set to 'false'`);
  }

  return function(error, req, res, next) {
    // NOTE (EK): If we are not dealing with a browser or it was an
    // XHR request then just skip this. This is primarily for
    // handling redirecting on an oauth failure.
    // console.log('Auth Error', error, options);
    if (!options.failureRedirect || req.xhr || req.is('json') || !req.accepts('html')) {
      return next(error);
    }

    // clear any previous JWT cookie
    if (options.cookie) {
      res.clearCookie(options.cookie.name);
    }

    debug('An authentication error occurred.', error);

    // Redirect to our failure route
    res.redirect(options.failureRedirect);
  };
};

export let setupSocketIOAuthentication = function(app, options = {}) {
  options = Object.assign({}, options);

  debug('Setting up Socket.io authentication middleware with options:', options);

  return function(socket) {
    let errorHandler = function(error) {
      socket.emit('unauthorized', error, function(){
        // TODO (EK): Maybe we support disconnecting the socket
        // if a certain number of authorization attempts have failed
        // for brute force protection
        // socket.disconnect('unauthorized');
      });

      throw error;
    };

    // Expose the request object to services and hooks
    // for Passport. This is normally a big no no.
    socket.feathers.req = socket.request;

    socket.on('authenticate', function(data) {
      // Authenticate the user using token strategy
      if (data.token) {
        if (typeof data.token !== 'string') {
          return errorHandler(new errors.BadRequest('Invalid token data type.'));
        }

        const params = Object.assign({ provider: 'socketio' }, data);

        // The token gets normalized in hook.params for REST so we'll stay with
        // convention and pass it as params using sockets.
        app.service(options.tokenEndpoint).create({}, params).then(response => {
          socket.feathers.token = response.token;
          socket.feathers.user = response.data;
          socket.emit('authenticated', response);
        }).catch(errorHandler);
      }
      // Authenticate the user using local auth strategy
      else {
        // Put our data in a fake req.body object to get local auth
        // with Passport to work because it checks res.body for the
        // username and password.
        let params = {
          provider: 'socketio',
          req: socket.request
        };

        params.req.body = data;

        app.service(options.localEndpoint).create(data, params).then(response => {
          socket.feathers.token = response.token;
          socket.feathers.user = response.data;
          socket.emit('authenticated', response);
        }).catch(errorHandler);
      }
    });

    socket.on('logout', function(callback) {

      // TODO (EK): Blacklist token
      try {
        delete socket.feathers.token;
        delete socket.feathers.user;
      }
      catch(error) {
        debug('There was an error logging out', error);
        return callback(new Error('There was an error logging out'));
      }

      callback();
    });
  };
};

// TODO (EK): DRY this up along with the code in setupSocketIOAuthentication
export let setupPrimusAuthentication = function(app, options = {}) {
  options = Object.assign({}, options);

  debug('Setting up Primus authentication middleware with options:', options);

  return function(socket) {
    let errorHandler = function(error) {
      socket.send('unauthorized', error);
      // TODO (EK): Maybe we support disconnecting the socket
      // if a certain number of authorization attempts have failed
      // for brute force protection
      // socket.end('unauthorized', error);
      throw error;
    };

    socket.request.feathers.req = socket.request;

    socket.on('authenticate', function(data) {
      // Authenticate the user using token strategy
      if (data.token) {
        if (typeof data.token !== 'string') {
          return errorHandler(new errors.BadRequest('Invalid token data type.'));
        }

        const params = Object.assign({ provider: 'primus' }, data);

        // The token gets normalized in hook.params for REST so we'll stay with
        // convention and pass it as params using sockets.
        app.service(options.tokenEndpoint).create({}, params).then(response => {
          socket.request.feathers.token = response.token;
          socket.request.feathers.user = response.data;
          socket.send('authenticated', response);
        }).catch(errorHandler);
      }
      // Authenticate the user using local auth strategy
      else {
        // Put our data in a fake req.body object to get local auth
        // with Passport to work because it checks res.body for the
        // username and password.
        let params = {
          provider: 'primus',
          req: socket.request
        };

        params.req.body = data;

        app.service(options.localEndpoint).create(data, params).then(response => {
          socket.request.feathers.token = response.token;
          socket.request.feathers.user = response.data;
          socket.send('authenticated', response);
        }).catch(errorHandler);
      }
    });

    socket.on('logout', function(callback) {

      // TODO (EK): Blacklist token
      try {
        delete socket.request.feathers.token;
        delete socket.request.feathers.user;
      }
      catch(error) {
        debug('There was an error logging out', error);
        return callback(new Error('There was an error logging out'));
      }

      callback();
    });
  };
};

export default {
  exposeConnectMiddleware,
  normalizeAuthToken,
  successfulLogin,
  failedLogin,
  setupSocketIOAuthentication,
  setupPrimusAuthentication
};<commit_msg>Update index.js<commit_after>import Debug from 'debug';
import errors from 'feathers-errors';

const debug = Debug('feathers-authentication:middleware');
const THIRTY_SECONDS = 30000;

// Usually this is a big no no but passport requires the
// request object to inspect req.body and req.query so we
// need to miss behave a bit. Don't do this in your own code!
export let exposeConnectMiddleware = function(req, res, next) {
  req.feathers.req = req;
  req.feathers.res = res;
  next();
};

// Make the authenticated passport user also available for REST services.
// We might need this for when we have session supported auth.
// export let exposeAuthenticatedUser = function(options = {}) {
//   return function(req, res, next) {
//     req.feathers.user = req.user;
//     next();
//   };
// };

// Make sure than an auth token passed in is available for hooks
// and services. This gracefully falls back from
// header -> body -> query string
export let normalizeAuthToken = function(options = {}) {
  debug('Setting up normalizeAuthToken middleware with options:', options);

  if (!options.header) {
    throw new Error(`'header' must be provided to normalizeAuthToken() middleware`);
  }

  return function(req, res, next) {
    let token = req.headers[options.header];

    // Check the header for the token (preferred method)
    if (token) {
      // if the value contains "bearer" or "Bearer" then cut that part out
      if ( /bearer/i.test(token) ) {
        token = token.split(' ')[1];
      }
    }

    // Check the body next if we still don't have a token
    if (req.body.token) {
      token = req.body.token;
      delete req.body.token;
    }
    // Finally, check the query string. (worst method but nice for quick local dev)
    else if (req.query.token) {
      token = req.query.token;
      delete req.query.token;
    }

    // Tack it on to our feathers object so that it is passed to services
    req.feathers.token = token;

    next();
  };
};

export let successfulLogin = function(options = {}) {
  debug('Setting up successfulLogin middleware with options:', options);

  if (options.cookie === undefined) {
    throw new Error(`'cookie' must be provided to successfulLogin() middleware or set to 'false'`);
  }

  return function(req, res, next) {
    // NOTE (EK): If we are not dealing with a browser or it was an
    // XHR request then just skip this. This is primarily for
    // handling the oauth redirects and for us to securely send the
    // JWT to the client in a cookie.
    if (!options.successRedirect || req.xhr || req.is('json') || !req.accepts('html')) {
      return next();
    }

    // If cookies are enabled set our JWT in a cookie.
    if (options.cookie) {
      // clear any previous JWT cookie
      res.clearCookie(options.cookie.name);

      // Only send back cookies when not in production or when in production and using HTTPS
      if (!req.secure && process.env.NODE_ENV === 'production') {
        console.error(`You should be using HTTPS in production! Refusing to send JWT in a cookie`);
      }
      else {
        const cookieOptions = Object.assign({}, options.cookie, { path: options.successRedirect });

        // If a custom expiry wasn't passed then set the expiration to be 30 seconds from now.
        if (cookieOptions.expires === undefined) {
          const expiry = new Date();
          expiry.setTime(expiry.getTime() + THIRTY_SECONDS);
          cookieOptions.expires = expiry;
        }

        if ( !(cookieOptions.expires instanceof Date) ) {
          throw new Error('cookie.expires must be a valid Date object');
        }

        res.cookie(options.cookie.name, res.data.token, cookieOptions);
      }
    }

    // Redirect to our success route
    res.redirect(options.successRedirect);
  };
};

export let failedLogin = function(options = {}) {
  debug('Setting up failedLogin middleware with options:', options);

  if (options.cookie === undefined) {
    throw new Error(`'cookie' must be provided to failedLogin() middleware or set to 'false'`);
  }

  return function(error, req, res, next) {
    // NOTE (EK): If we are not dealing with a browser or it was an
    // XHR request then just skip this. This is primarily for
    // handling redirecting on an oauth failure.
    // console.log('Auth Error', error, options);
    if (!options.failureRedirect || req.xhr || req.is('json') || !req.accepts('html')) {
      return next(error);
    }

    // clear any previous JWT cookie
    if (options.cookie) {
      res.clearCookie(options.cookie.name);
    }

    debug('An authentication error occurred.', error);

    // Redirect to our failure route
    res.redirect(options.failureRedirect);
  };
};

export let setupSocketIOAuthentication = function(app, options = {}) {
  options = Object.assign({}, options);

  debug('Setting up Socket.io authentication middleware with options:', options);

  return function(socket) {
    let errorHandler = function(error) {
      socket.emit('unauthorized', error, function(){
        // TODO (EK): Maybe we support disconnecting the socket
        // if a certain number of authorization attempts have failed
        // for brute force protection
        // socket.disconnect('unauthorized');
      });

      throw error;
    };

    // Expose the request object to services and hooks
    // for Passport. This is normally a big no no.
    socket.feathers.req = socket.request;

    socket.on('authenticate', function(data) {
      // Authenticate the user using token strategy
      if (data.token) {
        if (typeof data.token !== 'string') {
          return errorHandler(new errors.BadRequest('Invalid token data type.'));
        }

        const params = Object.assign({ provider: 'socketio' }, data);

        // The token gets normalized in hook.params for REST so we'll stay with
        // convention and pass it as params using sockets.
        app.service(options.tokenEndpoint).create({}, params).then(response => {
          socket.feathers.token = response.token;
          socket.feathers.user = response.data;
          socket.emit('authenticated', response);
        }).catch(errorHandler);
      }
      // Authenticate the user using local auth strategy
      else {
        // Put our data in a fake req.body object to get local auth
        // with Passport to work because it checks res.body for the
        // username and password.
        let params = {
          provider: 'socketio',
          req: socket.request
        };

        params.req.body = data;

        app.service(options.localEndpoint).create(data, params).then(response => {
          socket.feathers.token = response.token;
          socket.feathers.user = response.data;
          socket.emit('authenticated', response);
        }).catch(errorHandler);
      }
    });

    socket.on('logout', function(callback) {

      // TODO (EK): Blacklist token
      try {
        delete socket.feathers.token;
        delete socket.feathers.user;
      }
      catch(error) {
        debug('There was an error logging out', error);
        return callback(new Error('There was an error logging out'));
      }

      callback();
    });
  };
};

// TODO (EK): DRY this up along with the code in setupSocketIOAuthentication
export let setupPrimusAuthentication = function(app, options = {}) {
  options = Object.assign({}, options);

  debug('Setting up Primus authentication middleware with options:', options);

  return function(socket) {
    let errorHandler = function(error) {
      socket.send('unauthorized', error);
      // TODO (EK): Maybe we support disconnecting the socket
      // if a certain number of authorization attempts have failed
      // for brute force protection
      // socket.end('unauthorized', error);
      throw error;
    };

    socket.request.feathers.req = socket.request;

    socket.on('authenticate', function(data) {
      // Authenticate the user using token strategy
      if (data.token) {
        if (typeof data.token !== 'string') {
          return errorHandler(new errors.BadRequest('Invalid token data type.'));
        }

        const params = Object.assign({ provider: 'primus' }, data);

        // The token gets normalized in hook.params for REST so we'll stay with
        // convention and pass it as params using sockets.
        app.service(options.tokenEndpoint).create({}, params).then(response => {
          socket.request.feathers.token = response.token;
          socket.request.feathers.user = response.data;
          socket.send('authenticated', response);
        }).catch(errorHandler);
      }
      // Authenticate the user using local auth strategy
      else {
        // Put our data in a fake req.body object to get local auth
        // with Passport to work because it checks res.body for the
        // username and password.
        let params = {
          provider: 'primus',
          req: socket.request
        };

        params.req.body = data;

        app.service(options.localEndpoint).create(data, params).then(response => {
          socket.request.feathers.token = response.token;
          socket.request.feathers.user = response.data;
          socket.send('authenticated', response);
        }).catch(errorHandler);
      }
    });

    socket.on('logout', function(callback) {

      // TODO (EK): Blacklist token
      try {
        delete socket.request.feathers.token;
        delete socket.request.feathers.user;
      }
      catch(error) {
        debug('There was an error logging out', error);
        return callback(new Error('There was an error logging out'));
      }

      callback();
    });
  };
};

export default {
  exposeConnectMiddleware,
  normalizeAuthToken,
  successfulLogin,
  failedLogin,
  setupSocketIOAuthentication,
  setupPrimusAuthentication
};
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var contentService = require('../services/content-service');

var contentSchema = new Schema({
    title: {type: String, required: 'Please enter a title'},
    slug: {type: String, required: 'Please enter your first name'},
    body:  {type: String, required: 'Please enter your last name'},
    meta: {type: String, required: 'Please enter your email'},
    keywords: {type: String, required: 'Please enter your password'},
    created: {
        type: Date,
        default: Date.now
    }
});

contentSchema.path('slug').validate( function(value, next) {
    contentService.findContent(value, function(err, content) {
        if(err) {
            return next(false);
        }
        next(!content);
    });
}, 'That slug is already in use');

var Content = mongoose.model('Content', contentSchema);

module.exports = {
    Content: Content
}<commit_msg>v0.2.1: Added last modified date to schema<commit_after>var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var contentService = require('../services/content-service');

var contentSchema = new Schema({
    title: {type: String, required: 'Please enter a title'},
    slug: {type: String, required: 'Please enter your first name'},
    body:  {type: String, required: 'Please enter your last name'},
    meta: {type: String, required: 'Please enter your email'},
    keywords: {type: String, required: 'Please enter your password'},
    created: {
        type: Date,
        default: Date.now
    },
    lastmodified: {
        type: Date,
        default: Date.now
    }
});

contentSchema.path('slug').validate( function(value, next) {
    contentService.findContent(value, function(err, content) {
        if(err) {
            return next(false);
        }
        next(!content);
    });
}, 'That slug is already in use');

var Content = mongoose.model('Content', contentSchema);

module.exports = {
    Content: Content
}<|endoftext|>


<commit_before>import getForage from '../ajax/getForage';
import injectScouttowerBuffLinks from './injectScouttowerBuffLinks';
import {pCC} from '../support/layout';
import parseDateAsTimestamp from '../system/parseDateAsTimestamp';
import roundToString from '../common/roundToString';
import setForage from '../ajax/setForage';
import {createAnchor, createTBody, createTable} from '../common/cElement';
import {guideUrl, now} from '../support/dataObj';

function getTitanName(aRow) {
  return aRow.cells[0].firstElementChild.getAttribute('oldtitle');
}

function cooldownTracker(aRow, theTitans) {
  var myName = getTitanName(aRow).replace(' (Titan)', '');
  if (!theTitans[myName]) {
    var cooldown = aRow.nextElementSibling.cells[0].textContent;
    var coolTime = 0;
    if (cooldown.indexOf('until') !== -1) {
      coolTime = parseDateAsTimestamp(
        cooldown.replace('Cooldown until: ', ''));
    }
    theTitans[myName] = {
      cooldownText: cooldown,
      coolTime: coolTime,
      seen: 'yes'
    };
  }
}

function addRow(theTitans, trackerTable, titan) {
  if (theTitans[titan].coolTime < now) {return;}
  trackerTable.insertAdjacentHTML('beforeend',
    '
' + titan + '	' +
    '' +
    theTitans[titan].cooldownText + '	' +
    theTitans[titan].seen + '
');
}

function displayTracker(parentTable, theTitans) {
  var trackerTable = createTable({className: 'fshTTracker'});
  var tBody = createTBody({
    innerHTML: '
Titan	' +
      'Cooldown	' +
      'Visible
'
  });
  trackerTable.appendChild(tBody);
  Object.keys(theTitans).forEach(addRow.bind(null, theTitans, tBody));

  var newRow = parentTable.insertRow(5);
  var newCell = newRow.insertCell(-1);
  newCell.colSpan = 3;
  newCell.appendChild(trackerTable);
}

function addMissingTitansFromOld(oldTitans, newTitans) {
  if (!oldTitans) {return;}
  Object.keys(oldTitans).forEach(function(oldTitan) {
    if (newTitans[oldTitan]) {return;}
    if (oldTitans[oldTitan].coolTime <= now) {return;}
    newTitans[oldTitan] = {
      cooldownText: oldTitans[oldTitan].cooldownText,
      coolTime: oldTitans[oldTitan].coolTime,
      seen: 'no'
    };
  });
}

export function getTitanString(guildKills, totalHP, currentHP) {
  var numberOfKillsToSecure = Math.ceil(totalHP / 2 + 1);
  if (guildKills >= numberOfKillsToSecure) {
    return 'Secured';
  }
  var remainingKills = numberOfKillsToSecure - guildKills;
  if (remainingKills > currentHP) {
    return 'Cannot Secure';
  }
  return '' + remainingKills + ' to secure';
}

export function getKillsPct(currentNumberOfKills, guildKills) {
  if (currentNumberOfKills === 0) {return 0;}
  return guildKills * 100 / currentNumberOfKills;
}

function killsSummary(aRow) {
  var titanHP = aRow.cells[2].textContent;
  if (titanHP.indexOf('-') !== -1) {return;}
  var guildKills = Number(aRow.cells[3].textContent);
  var titanHPArray = titanHP.split('/');
  var currentHP = Number(titanHPArray[0]);
  var totalHP = Number(titanHPArray[1]);
  aRow.cells[3].insertAdjacentHTML('beforeend',
    '
 (' +
    roundToString(getKillsPct(totalHP - currentHP, guildKills), 2) +
    '% Current
' + roundToString(guildKills * 100 / totalHP, 2) +
    '% Total
' + getTitanString(guildKills, totalHP, currentHP) + ')');
}

function guideLink(aRow) {
  var myName = encodeURIComponent(getTitanName(aRow));
  var myImg = aRow.cells[0].firstElementChild;
  var myLink = createAnchor({
    href: guideUrl + 'creatures&search_name=' + myName,
    target: '_blank'
  });
  myLink.appendChild(myImg);
  aRow.cells[0].appendChild(myLink);
}

function gotOldTitans(oldTitans) {
  var titanTables = pCC.getElementsByTagName('table');
  injectScouttowerBuffLinks(titanTables);
  var titanTable = titanTables[1];
  var newTitans = {};
  for (var i = 1; i < titanTable.rows.length - 1; i += 6) {
    var aRow = titanTable.rows[i];
    killsSummary(aRow);
    cooldownTracker(aRow, newTitans); // Pref
    guideLink(aRow);
  }
  addMissingTitansFromOld(oldTitans, newTitans); // Pref
  displayTracker(titanTables[0], newTitans); // Pref
  setForage('fsh_titans', newTitans); // Pref
}

export default function injectScouttower() {
  getForage('fsh_titans').done(gotOldTitans); // Pref
}
<commit_msg>test for jQuery in injectScouttower<commit_after>import getForage from '../ajax/getForage';
import injectScouttowerBuffLinks from './injectScouttowerBuffLinks';
import {pCC} from '../support/layout';
import parseDateAsTimestamp from '../system/parseDateAsTimestamp';
import roundToString from '../common/roundToString';
import setForage from '../ajax/setForage';
import {createAnchor, createTBody, createTable} from '../common/cElement';
import {guideUrl, now} from '../support/dataObj';

function getTitanName(aRow) {
  return aRow.cells[0].firstElementChild.getAttribute('oldtitle');
}

function cooldownTracker(aRow, theTitans) {
  var myName = getTitanName(aRow).replace(' (Titan)', '');
  if (!theTitans[myName]) {
    var cooldown = aRow.nextElementSibling.cells[0].textContent;
    var coolTime = 0;
    if (cooldown.indexOf('until') !== -1) {
      coolTime = parseDateAsTimestamp(
        cooldown.replace('Cooldown until: ', ''));
    }
    theTitans[myName] = {
      cooldownText: cooldown,
      coolTime: coolTime,
      seen: 'yes'
    };
  }
}

function addRow(theTitans, trackerTable, titan) {
  if (theTitans[titan].coolTime < now) {return;}
  trackerTable.insertAdjacentHTML('beforeend',
    '
' + titan + '	' +
    '' +
    theTitans[titan].cooldownText + '	' +
    theTitans[titan].seen + '
');
}

function displayTracker(parentTable, theTitans) {
  var trackerTable = createTable({className: 'fshTTracker'});
  var tBody = createTBody({
    innerHTML: '
Titan	' +
      'Cooldown	' +
      'Visible
'
  });
  trackerTable.appendChild(tBody);
  Object.keys(theTitans).forEach(addRow.bind(null, theTitans, tBody));

  var newRow = parentTable.insertRow(5);
  var newCell = newRow.insertCell(-1);
  newCell.colSpan = 3;
  newCell.appendChild(trackerTable);
}

function addMissingTitansFromOld(oldTitans, newTitans) {
  if (!oldTitans) {return;}
  Object.keys(oldTitans).forEach(function(oldTitan) {
    if (newTitans[oldTitan]) {return;}
    if (oldTitans[oldTitan].coolTime <= now) {return;}
    newTitans[oldTitan] = {
      cooldownText: oldTitans[oldTitan].cooldownText,
      coolTime: oldTitans[oldTitan].coolTime,
      seen: 'no'
    };
  });
}

export function getTitanString(guildKills, totalHP, currentHP) {
  var numberOfKillsToSecure = Math.ceil(totalHP / 2 + 1);
  if (guildKills >= numberOfKillsToSecure) {
    return 'Secured';
  }
  var remainingKills = numberOfKillsToSecure - guildKills;
  if (remainingKills > currentHP) {
    return 'Cannot Secure';
  }
  return '' + remainingKills + ' to secure';
}

export function getKillsPct(currentNumberOfKills, guildKills) {
  if (currentNumberOfKills === 0) {return 0;}
  return guildKills * 100 / currentNumberOfKills;
}

function killsSummary(aRow) {
  var titanHP = aRow.cells[2].textContent;
  if (titanHP.indexOf('-') !== -1) {return;}
  var guildKills = Number(aRow.cells[3].textContent);
  var titanHPArray = titanHP.split('/');
  var currentHP = Number(titanHPArray[0]);
  var totalHP = Number(titanHPArray[1]);
  aRow.cells[3].insertAdjacentHTML('beforeend',
    '
 (' +
    roundToString(getKillsPct(totalHP - currentHP, guildKills), 2) +
    '% Current
' + roundToString(guildKills * 100 / totalHP, 2) +
    '% Total
' + getTitanString(guildKills, totalHP, currentHP) + ')');
}

function guideLink(aRow) {
  var myName = encodeURIComponent(getTitanName(aRow));
  var myImg = aRow.cells[0].firstElementChild;
  var myLink = createAnchor({
    href: guideUrl + 'creatures&search_name=' + myName,
    target: '_blank'
  });
  myLink.appendChild(myImg);
  aRow.cells[0].appendChild(myLink);
}

function gotOldTitans(oldTitans) {
  var titanTables = pCC.getElementsByTagName('table');
  injectScouttowerBuffLinks(titanTables);
  var titanTable = titanTables[1];
  var newTitans = {};
  for (var i = 1; i < titanTable.rows.length - 1; i += 6) {
    var aRow = titanTable.rows[i];
    killsSummary(aRow);
    cooldownTracker(aRow, newTitans); // Pref
    guideLink(aRow);
  }
  addMissingTitansFromOld(oldTitans, newTitans); // Pref
  displayTracker(titanTables[0], newTitans); // Pref
  setForage('fsh_titans', newTitans); // Pref
}

export default function injectScouttower() { // jQuery.min
  if (typeof $ !== 'function') {return;}
  getForage('fsh_titans').done(gotOldTitans); // Pref
}
<|endoftext|>


<commit_before>/**
 * This snippets listens for unauthenticated ajax requests and forces the browser to reload the current site to start
 * the normal logout handling with redirecting to the current page.
 */
$(document).ajaxError(function(event, jqxhr) {
    if(jqxhr.status === 401) {
        location.reload();
    }
});
<commit_msg>Code Cleanup: avoid trailing whitespaces<commit_after>/**
 * This snippets listens for unauthenticated ajax requests and forces the browser to reload the current site to start
 * the normal logout handling with redirecting to the current page.
 */
$(document).ajaxError(function (event, jqxhr) {
    if (jqxhr.status === 401) {
        location.reload();
    }
});
<|endoftext|>


<commit_before>import macro              from 'vtk.js/Sources/macro';
import vtkDataSet         from 'vtk.js/Sources/Common/DataModel/DataSet';
import vtkStructuredData  from 'vtk.js/Sources/Common/DataModel/StructuredData';
import { StructuredType } from 'vtk.js/Sources/Common/DataModel/StructuredData/Constants';
import { quat, vec3, mat3, mat4 } from 'gl-matrix';

const { vtkErrorMacro } = macro;

// ----------------------------------------------------------------------------
// vtkImageData methods
// ----------------------------------------------------------------------------

function vtkImageData(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkImageData');

  publicAPI.setExtent = (...inExtent) => {
    if (model.deleted) {
      vtkErrorMacro('instance deleted - cannot call any method');
      return;
    }

    if (!inExtent || inExtent.length !== 6) {
      return;
    }

    let changeDetected = false;
    model.extent.forEach((item, index) => {
      if (item !== inExtent[index]) {
        if (changeDetected) {
          return;
        }
        changeDetected = true;
      }
    });

    if (changeDetected) {
      model.extent = [].concat(inExtent);
      model.dataDescription = vtkStructuredData.getDataDescriptionFromExtent(model.extent);
      publicAPI.modified();
    }
  };

  publicAPI.setDimensions = (...dims) => {
    var i;
    var j;
    var k;

    if (model.deleted) {
      vtkErrorMacro('instance deleted - cannot call any method');
      return;
    }

    if (dims.length === 1) {
      const array = dims[0];
      i = array[0];
      j = array[1];
      k = array[2];
    } else if (dims.length === 3) {
      i = dims[0];
      j = dims[1];
      k = dims[2];
    } else {
      vtkErrorMacro('Bad dimension specification');
      return;
    }

    publicAPI.setExtent(0, i - 1, 0, j - 1, 0, k - 1);
  };

  publicAPI.getDimensions = () => [
    (model.extent[1] - model.extent[0]) + 1,
    (model.extent[3] - model.extent[2]) + 1,
    (model.extent[5] - model.extent[4]) + 1,
  ];

  publicAPI.getNumberOfCells = () => {
    const dims = publicAPI.getDimensions();
    let nCells = 1;

    for (let i = 0; i < 3; i++) {
      if (dims[i] === 0) {
        return 0;
      }
      if (dims[i] > 1) {
        nCells *= (dims[i] - 1);
      }
    }

    return nCells;
  };

  publicAPI.getNumberOfPoints = () => {
    const dims = publicAPI.getDimensions();
    return dims[0] * dims[1] * dims[2];
  };

  publicAPI.getPoint = (index) => {
    const dims = publicAPI.getDimensions();
    const ijk = vec3.fromValues(0, 0, 0);
    const coords = [0, 0, 0];

    if (dims[0] === 0 || dims[1] === 0 || dims[2] === 0) {
      vtkErrorMacro('Requesting a point from an empty image.');
      return null;
    }

    switch (model.dataDescription) {
      case StructuredType.EMPTY:
        return null;

      case StructuredType.SINGLE_POINT:
        break;

      case StructuredType.X_LINE:
        ijk[0] = index;
        break;

      case StructuredType.Y_LINE:
        ijk[1] = index;
        break;

      case StructuredType.Z_LINE:
        ijk[2] = index;
        break;

      case StructuredType.XY_PLANE:
        ijk[0] = index % dims[0];
        ijk[1] = index / dims[0];
        break;

      case StructuredType.YZ_PLANE:
        ijk[1] = index % dims[1];
        ijk[2] = index / dims[1];
        break;

      case StructuredType.XZ_PLANE:
        ijk[0] = index % dims[0];
        ijk[2] = index / dims[0];
        break;

      case StructuredType.XYZ_GRID:
        ijk[0] = index % dims[0];
        ijk[1] = (index / dims[0]) % dims[1];
        ijk[2] = index / (dims[0] * dims[1]);
        break;

      default:
        vtkErrorMacro('Invalid dataDescription');
        break;
    }

    const vout = vec3.create();
    publicAPI.indexToWorldVec3(ijk, vout);
    vec3.copy(coords, vout);
    return coords;
  };

  // vtkCell *GetCell(vtkIdType cellId) VTK_OVERRIDE;
  // void GetCell(vtkIdType cellId, vtkGenericCell *cell) VTK_OVERRIDE;
  // void GetCellBounds(vtkIdType cellId, double bounds[6]) VTK_OVERRIDE;
  // virtual vtkIdType FindPoint(double x, double y, double z)
  // {
  //   return this->vtkDataSet::FindPoint(x, y, z);
  // }
  // vtkIdType FindPoint(double x[3]) VTK_OVERRIDE;
  // vtkIdType FindCell(
  //   double x[3], vtkCell *cell, vtkIdType cellId, double tol2,
  //   int& subId, double pcoords[3], double *weights) VTK_OVERRIDE;
  // vtkIdType FindCell(
  //   double x[3], vtkCell *cell, vtkGenericCell *gencell,
  //   vtkIdType cellId, double tol2, int& subId,
  //   double pcoords[3], double *weights) VTK_OVERRIDE;
  // vtkCell *FindAndGetCell(double x[3], vtkCell *cell, vtkIdType cellId,
  //                                 double tol2, int& subId, double pcoords[3],
  //                                 double *weights) VTK_OVERRIDE;
  // int GetCellType(vtkIdType cellId) VTK_OVERRIDE;
  // void GetCellPoints(vtkIdType cellId, vtkIdList *ptIds) VTK_OVERRIDE
  //   {vtkStructuredData::GetCellPoints(cellId,ptIds,this->DataDescription,
  //                                     this->GetDimensions());}
  // void GetPointCells(vtkIdType ptId, vtkIdList *cellIds) VTK_OVERRIDE
  //   {vtkStructuredData::GetPointCells(ptId,cellIds,this->GetDimensions());}
  // void ComputeBounds() VTK_OVERRIDE;
  // int GetMaxCellSize() VTK_OVERRIDE {return 8;}; //voxel is the largest

  publicAPI.getBounds = () => publicAPI.extentToBounds(model.extent);

  publicAPI.extentToBounds = (ex) => {
    const corners = [
      ex[0], ex[2], ex[4],
      ex[1], ex[2], ex[4],
      ex[0], ex[3], ex[4],
      ex[1], ex[3], ex[4],
      ex[0], ex[2], ex[5],
      ex[1], ex[2], ex[5],
      ex[0], ex[3], ex[5],
      ex[1], ex[3], ex[5]];

    const idx = vec3.fromValues(corners[0], corners[1], corners[2]);
    const vout = vec3.create();
    publicAPI.indexToWorldVec3(idx, vout);
    const bounds = [vout[0], vout[0], vout[1], vout[1], vout[2], vout[2]];
    for (let i = 3; i < 24; i += 3) {
      vec3.set(idx, corners[i], corners[i + 1], corners[i + 2]);
      publicAPI.indexToWorldVec3(idx, vout);
      if (vout[0] < bounds[0]) { bounds[0] = vout[0]; }
      if (vout[1] < bounds[2]) { bounds[2] = vout[1]; }
      if (vout[2] < bounds[4]) { bounds[4] = vout[2]; }
      if (vout[0] > bounds[1]) { bounds[1] = vout[0]; }
      if (vout[1] > bounds[3]) { bounds[3] = vout[1]; }
      if (vout[2] > bounds[5]) { bounds[5] = vout[2]; }
    }

    return bounds;
  };

  publicAPI.computeTransforms = () => {
    const rotq = quat.create();
    quat.fromMat3(rotq, model.direction);
    const trans = vec3.fromValues(
      model.origin[0], model.origin[1], model.origin[2]);
    const scale = vec3.fromValues(
      model.spacing[0], model.spacing[1], model.spacing[2]);
    mat4.fromRotationTranslationScale(model.indexToWorld, rotq, trans, scale);
    mat4.invert(model.worldToIndex, model.indexToWorld);
  };

  //
  // The direction matrix is a 3x3 basis for the I, J, K axes
  // of the image. The rows of the matrix correspond to the
  // axes directions in world coordinates. Direction must
  // form an orthonormal basis, results are undefined if
  // it is not.
  //
  publicAPI.setDirection = (...args) => {
    if (model.deleted) {
      vtkErrorMacro('instance deleted - cannot call any method');
      return false;
    }

    let array = args;
    // allow an array passed as a single arg.
    if (array.length === 1 && Array.isArray(array[0])) {
      array = array[0];
    }

    if (array.length !== 9) {
      throw new RangeError('Invalid number of values for array setter');
    }
    let changeDetected = false;
    model.direction.forEach((item, index) => {
      if (item !== array[index]) {
        if (changeDetected) {
          return;
        }
        changeDetected = true;
      }
    });

    if (changeDetected) {
      for (let i = 0; i < 9; ++i) {
        model.direction[i] = array[i];
      }
      publicAPI.modified();
    }
    return true;
  };

  // this is the fast version, requires vec3 arguments
  publicAPI.indexToWorldVec3 = (vin, vout) => {
    vec3.transformMat4(vout, vin, model.indexToWorld);
  };

  // slow version for generic arrays
  publicAPI.indexToWorld = (ain, aout) => {
    const vin = vec3.fromValues(ain[0], ain[1], ain[2]);
    const vout = vec3.create();
    vec3.transformMat4(vout, vin, model.indexToWorld);
    vec3.copy(aout, vout);
  };

  // this is the fast version, requires vec3 arguments
  publicAPI.worldToIndexVec3 = (vin, vout) => {
    vec3.transformMat4(vout, vin, model.worldToIndex);
  };

  // slow version for generic arrays
  publicAPI.worldToIndex = (ain, aout) => {
    const vin = vec3.fromValues(ain[0], ain[1], ain[2]);
    const vout = vec3.create();
    vec3.transformMat4(vout, vin, model.worldToIndex);
    vec3.copy(aout, vout);
  };

  publicAPI.onModified(publicAPI.computeTransforms);
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
  direction: null,  // a mat3
  indexToWorld: null, // a mat4
  worldToIndex: null, // a mat4
  spacing: [1.0, 1.0, 1.0],
  origin: [0.0, 0.0, 0.0],
  extent: [0, -1, 0, -1, 0, -1],
  dataDescription: StructuredType.EMPTY,
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Inheritance
  vtkDataSet.extend(publicAPI, model, initialValues);

  if (!model.direction) {
    model.direction = mat3.create();
  } else if (Array.isArray(model.direction)) {
    const dvals = model.direction.slice(0);
    model.direction = mat3.create();
    for (let i = 0; i < 9; ++i) {
      model.direction[i] = dvals[i];
    }
  }

  model.indexToWorld = mat4.create();
  model.worldToIndex = mat4.create();

  // Set/Get methods
  macro.get(publicAPI, model, [
    'direction',
    'indexToWorld',
    'worldToIndex',
  ]);
  macro.setGetArray(publicAPI, model, ['origin', 'spacing'], 3);
  macro.getArray(publicAPI, model, ['extent'], 6);

  // Object specific methods
  vtkImageData(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkImageData');

// ----------------------------------------------------------------------------

export default { newInstance, extend };
<commit_msg>fix(ImageData): Ensure call to computeTransforms() at construction<commit_after>import macro              from 'vtk.js/Sources/macro';
import vtkDataSet         from 'vtk.js/Sources/Common/DataModel/DataSet';
import vtkStructuredData  from 'vtk.js/Sources/Common/DataModel/StructuredData';
import { StructuredType } from 'vtk.js/Sources/Common/DataModel/StructuredData/Constants';
import { quat, vec3, mat3, mat4 } from 'gl-matrix';

const { vtkErrorMacro } = macro;

// ----------------------------------------------------------------------------
// vtkImageData methods
// ----------------------------------------------------------------------------

function vtkImageData(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkImageData');

  publicAPI.setExtent = (...inExtent) => {
    if (model.deleted) {
      vtkErrorMacro('instance deleted - cannot call any method');
      return;
    }

    if (!inExtent || inExtent.length !== 6) {
      return;
    }

    let changeDetected = false;
    model.extent.forEach((item, index) => {
      if (item !== inExtent[index]) {
        if (changeDetected) {
          return;
        }
        changeDetected = true;
      }
    });

    if (changeDetected) {
      model.extent = [].concat(inExtent);
      model.dataDescription = vtkStructuredData.getDataDescriptionFromExtent(model.extent);
      publicAPI.modified();
    }
  };

  publicAPI.setDimensions = (...dims) => {
    var i;
    var j;
    var k;

    if (model.deleted) {
      vtkErrorMacro('instance deleted - cannot call any method');
      return;
    }

    if (dims.length === 1) {
      const array = dims[0];
      i = array[0];
      j = array[1];
      k = array[2];
    } else if (dims.length === 3) {
      i = dims[0];
      j = dims[1];
      k = dims[2];
    } else {
      vtkErrorMacro('Bad dimension specification');
      return;
    }

    publicAPI.setExtent(0, i - 1, 0, j - 1, 0, k - 1);
  };

  publicAPI.getDimensions = () => [
    (model.extent[1] - model.extent[0]) + 1,
    (model.extent[3] - model.extent[2]) + 1,
    (model.extent[5] - model.extent[4]) + 1,
  ];

  publicAPI.getNumberOfCells = () => {
    const dims = publicAPI.getDimensions();
    let nCells = 1;

    for (let i = 0; i < 3; i++) {
      if (dims[i] === 0) {
        return 0;
      }
      if (dims[i] > 1) {
        nCells *= (dims[i] - 1);
      }
    }

    return nCells;
  };

  publicAPI.getNumberOfPoints = () => {
    const dims = publicAPI.getDimensions();
    return dims[0] * dims[1] * dims[2];
  };

  publicAPI.getPoint = (index) => {
    const dims = publicAPI.getDimensions();
    const ijk = vec3.fromValues(0, 0, 0);
    const coords = [0, 0, 0];

    if (dims[0] === 0 || dims[1] === 0 || dims[2] === 0) {
      vtkErrorMacro('Requesting a point from an empty image.');
      return null;
    }

    switch (model.dataDescription) {
      case StructuredType.EMPTY:
        return null;

      case StructuredType.SINGLE_POINT:
        break;

      case StructuredType.X_LINE:
        ijk[0] = index;
        break;

      case StructuredType.Y_LINE:
        ijk[1] = index;
        break;

      case StructuredType.Z_LINE:
        ijk[2] = index;
        break;

      case StructuredType.XY_PLANE:
        ijk[0] = index % dims[0];
        ijk[1] = index / dims[0];
        break;

      case StructuredType.YZ_PLANE:
        ijk[1] = index % dims[1];
        ijk[2] = index / dims[1];
        break;

      case StructuredType.XZ_PLANE:
        ijk[0] = index % dims[0];
        ijk[2] = index / dims[0];
        break;

      case StructuredType.XYZ_GRID:
        ijk[0] = index % dims[0];
        ijk[1] = (index / dims[0]) % dims[1];
        ijk[2] = index / (dims[0] * dims[1]);
        break;

      default:
        vtkErrorMacro('Invalid dataDescription');
        break;
    }

    const vout = vec3.create();
    publicAPI.indexToWorldVec3(ijk, vout);
    vec3.copy(coords, vout);
    return coords;
  };

  // vtkCell *GetCell(vtkIdType cellId) VTK_OVERRIDE;
  // void GetCell(vtkIdType cellId, vtkGenericCell *cell) VTK_OVERRIDE;
  // void GetCellBounds(vtkIdType cellId, double bounds[6]) VTK_OVERRIDE;
  // virtual vtkIdType FindPoint(double x, double y, double z)
  // {
  //   return this->vtkDataSet::FindPoint(x, y, z);
  // }
  // vtkIdType FindPoint(double x[3]) VTK_OVERRIDE;
  // vtkIdType FindCell(
  //   double x[3], vtkCell *cell, vtkIdType cellId, double tol2,
  //   int& subId, double pcoords[3], double *weights) VTK_OVERRIDE;
  // vtkIdType FindCell(
  //   double x[3], vtkCell *cell, vtkGenericCell *gencell,
  //   vtkIdType cellId, double tol2, int& subId,
  //   double pcoords[3], double *weights) VTK_OVERRIDE;
  // vtkCell *FindAndGetCell(double x[3], vtkCell *cell, vtkIdType cellId,
  //                                 double tol2, int& subId, double pcoords[3],
  //                                 double *weights) VTK_OVERRIDE;
  // int GetCellType(vtkIdType cellId) VTK_OVERRIDE;
  // void GetCellPoints(vtkIdType cellId, vtkIdList *ptIds) VTK_OVERRIDE
  //   {vtkStructuredData::GetCellPoints(cellId,ptIds,this->DataDescription,
  //                                     this->GetDimensions());}
  // void GetPointCells(vtkIdType ptId, vtkIdList *cellIds) VTK_OVERRIDE
  //   {vtkStructuredData::GetPointCells(ptId,cellIds,this->GetDimensions());}
  // void ComputeBounds() VTK_OVERRIDE;
  // int GetMaxCellSize() VTK_OVERRIDE {return 8;}; //voxel is the largest

  publicAPI.getBounds = () => publicAPI.extentToBounds(model.extent);

  publicAPI.extentToBounds = (ex) => {
    const corners = [
      ex[0], ex[2], ex[4],
      ex[1], ex[2], ex[4],
      ex[0], ex[3], ex[4],
      ex[1], ex[3], ex[4],
      ex[0], ex[2], ex[5],
      ex[1], ex[2], ex[5],
      ex[0], ex[3], ex[5],
      ex[1], ex[3], ex[5]];

    const idx = vec3.fromValues(corners[0], corners[1], corners[2]);
    const vout = vec3.create();
    publicAPI.indexToWorldVec3(idx, vout);
    const bounds = [vout[0], vout[0], vout[1], vout[1], vout[2], vout[2]];
    for (let i = 3; i < 24; i += 3) {
      vec3.set(idx, corners[i], corners[i + 1], corners[i + 2]);
      publicAPI.indexToWorldVec3(idx, vout);
      if (vout[0] < bounds[0]) { bounds[0] = vout[0]; }
      if (vout[1] < bounds[2]) { bounds[2] = vout[1]; }
      if (vout[2] < bounds[4]) { bounds[4] = vout[2]; }
      if (vout[0] > bounds[1]) { bounds[1] = vout[0]; }
      if (vout[1] > bounds[3]) { bounds[3] = vout[1]; }
      if (vout[2] > bounds[5]) { bounds[5] = vout[2]; }
    }

    return bounds;
  };

  publicAPI.computeTransforms = () => {
    const rotq = quat.create();
    quat.fromMat3(rotq, model.direction);
    const trans = vec3.fromValues(
      model.origin[0], model.origin[1], model.origin[2]);
    const scale = vec3.fromValues(
      model.spacing[0], model.spacing[1], model.spacing[2]);
    mat4.fromRotationTranslationScale(model.indexToWorld, rotq, trans, scale);
    mat4.invert(model.worldToIndex, model.indexToWorld);
  };

  //
  // The direction matrix is a 3x3 basis for the I, J, K axes
  // of the image. The rows of the matrix correspond to the
  // axes directions in world coordinates. Direction must
  // form an orthonormal basis, results are undefined if
  // it is not.
  //
  publicAPI.setDirection = (...args) => {
    if (model.deleted) {
      vtkErrorMacro('instance deleted - cannot call any method');
      return false;
    }

    let array = args;
    // allow an array passed as a single arg.
    if (array.length === 1 && Array.isArray(array[0])) {
      array = array[0];
    }

    if (array.length !== 9) {
      throw new RangeError('Invalid number of values for array setter');
    }
    let changeDetected = false;
    model.direction.forEach((item, index) => {
      if (item !== array[index]) {
        if (changeDetected) {
          return;
        }
        changeDetected = true;
      }
    });

    if (changeDetected) {
      for (let i = 0; i < 9; ++i) {
        model.direction[i] = array[i];
      }
      publicAPI.modified();
    }
    return true;
  };

  // this is the fast version, requires vec3 arguments
  publicAPI.indexToWorldVec3 = (vin, vout) => {
    vec3.transformMat4(vout, vin, model.indexToWorld);
  };

  // slow version for generic arrays
  publicAPI.indexToWorld = (ain, aout) => {
    const vin = vec3.fromValues(ain[0], ain[1], ain[2]);
    const vout = vec3.create();
    vec3.transformMat4(vout, vin, model.indexToWorld);
    vec3.copy(aout, vout);
  };

  // this is the fast version, requires vec3 arguments
  publicAPI.worldToIndexVec3 = (vin, vout) => {
    vec3.transformMat4(vout, vin, model.worldToIndex);
  };

  // slow version for generic arrays
  publicAPI.worldToIndex = (ain, aout) => {
    const vin = vec3.fromValues(ain[0], ain[1], ain[2]);
    const vout = vec3.create();
    vec3.transformMat4(vout, vin, model.worldToIndex);
    vec3.copy(aout, vout);
  };

  // Make sure the transform is correct
  publicAPI.onModified(publicAPI.computeTransforms);
  publicAPI.computeTransforms();
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
  direction: null,  // a mat3
  indexToWorld: null, // a mat4
  worldToIndex: null, // a mat4
  spacing: [1.0, 1.0, 1.0],
  origin: [0.0, 0.0, 0.0],
  extent: [0, -1, 0, -1, 0, -1],
  dataDescription: StructuredType.EMPTY,
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Inheritance
  vtkDataSet.extend(publicAPI, model, initialValues);

  if (!model.direction) {
    model.direction = mat3.create();
  } else if (Array.isArray(model.direction)) {
    const dvals = model.direction.slice(0);
    model.direction = mat3.create();
    for (let i = 0; i < 9; ++i) {
      model.direction[i] = dvals[i];
    }
  }

  model.indexToWorld = mat4.create();
  model.worldToIndex = mat4.create();

  // Set/Get methods
  macro.get(publicAPI, model, [
    'direction',
    'indexToWorld',
    'worldToIndex',
  ]);
  macro.setGetArray(publicAPI, model, ['origin', 'spacing'], 3);
  macro.getArray(publicAPI, model, ['extent'], 6);

  // Object specific methods
  vtkImageData(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkImageData');

// ----------------------------------------------------------------------------

export default { newInstance, extend };
<|endoftext|>