H. Chad Lane

57 papers A* 2A 12B 3C 3Misc 6Journal 12Unranked 11
YearRankTypeTitle / Venue / Authors
2025 conf
AIED (3)
Samuel Hum, Matt Gadbury, Jeffrey Ginger, Kobe Duda, H. Chad Lane
2024 conf
AIED (2)
Samuel Hum, Evan Shipley, Matt Gadbury, H. Chad Lane, Jeffrey Ginger
2024 A* conf
AAAI
Jay Mahajan, Samuel Hum, Jack Henhapl, Diya Yunus, Matthew Gadbury, Emi Brown, Jeffrey Ginger, H. Chad Lane
2023 conf
AIED (Posters/Late Breaking Results/...)
Matthew Gadbury, H. Chad Lane
2023 J jnl
Int. J. Artif. Intell. Educ.
H. Chad Lane
2023 J jnl
CoRR
Jay Mahajan, Samuel Hum, Jack Henhapl, Diya Yunus, Matthew Gadbury, Emi Brown, Jeffrey Ginger, H. Chad Lane
2022 conf
AIED (2)
Samuel Hum, Frank Stinar, Haejin Lee, Jeffrey Ginger, H. Chad Lane
2022 Misc conf
FLAIRS
Jay Mahajan, Samuel Hum, Jeffrey Ginger, H. Chad Lane
2022 conf
AIED (2)
Matt Gadbury, H. Chad Lane
2022 ch.
The Handbook on Socially Interactive Agents (2)
H. Chad Lane, Noah L. Schroeder
2021 J jnl
Hum. Factors
Daniel G. Morrow, H. Chad Lane, Wendy A. Rogers
2021 ed.
CSEDU (Selected Papers)
H. Chad Lane, Susan Zvacek, James Uhomoibhi
2020 conf
ICLS
Sherry Yi, Matt Gadbury, H. Chad Lane
2020 ed.
CSEDU (Selected Papers)
H. Chad Lane, Susan Zvacek, James Uhomoibhi
2020 ed.
CSEDU (1)
H. Chad Lane, Susan Zvacek, James Uhomoibhi
2020 ed.
CSEDU (2)
H. Chad Lane, Susan Zvacek, James Uhomoibhi
2019 conf
AIED (2)
Matthew Jensen Hays, Aaron Richard Glick, H. Chad Lane
2019 ed.
CSEDU (1)
H. Chad Lane, Susan Zvacek, James Uhomoibhi
2019 ed.
CSEDU (2)
H. Chad Lane, Susan Zvacek, James Uhomoibhi
2019 C conf
FDG
Sherry Yi, H. Chad Lane, Ömer Delialioglu
2018 conf
CSEDU (1)
H. Chad Lane
2017 C conf
ICCE
H. Chad Lane, Brian Guerrero, Neil Comins
2017 C conf
ICCE
H. Chad Lane, Sherry Yi, Brian Guerrero, Neil Comins
2016 J jnl
Int. J. Artif. Intell. Educ.
H. Chad Lane, Gordon McCalla, Chee-Kit Looi, Susan Bull
2016 J jnl
Computer
H. Chad Lane, David A. Forsyth
2015 A conf
AIED
H. Chad Lane, Mark G. Core, Matthew J. Hays, Daniel Auerbach, Milton Rosenberg
2013 J jnl
AI Mag.
Beverly Park Woolf, H. Chad Lane, Vinay K. Chaudhri, Janet L. Kolodner
2013 A ed.
AIED
H. Chad Lane, Kalina Yacef, Jack Mostow, Philip I. Pavlik
2013 J jnl
AI Mag.
Vinay K. Chaudhri, H. Chad Lane, Dave Gunning, Jeremy Roschelle
2013 J jnl
AI Mag.
Vinay K. Chaudhri, H. Chad Lane, David Gunning, Jeremy Roschelle
2013 conf
AIED Workshops
Matthew J. Hays, H. Chad Lane, Daniel Auerbach
2013 A conf
AIED
H. Chad Lane, Clara Cahill, Susan Foutz, Daniel Auerbach, Dan Noren, Catherine Lussenhop, William R. Swartout
2013 J jnl
AI Mag.
William R. Swartout, Ron Artstein, Eric Forbell, Susan Foutz, H. Chad Lane, Belinda Lange, Jacquelyn Ford Morie, Skip Rizzo, David R. Traum
2012 ed.
C5
Ian Piumarta, Lori Weiss, H. Chad Lane, Louis-Philippe Morency
2011 A conf
AIED
H. Chad Lane, Dan Noren, Daniel Auerbach, Mike Birch, William R. Swartout
2011 A conf
AIED
H. Chad Lane, Brent Martin
2010 Misc conf
AIMSA
H. Chad Lane
2010 B conf
Intelligent Tutoring Systems (1)
H. Chad Lane, Matthew J. Hays, Daniel Auerbach, Mark G. Core
2010 B conf
Intelligent Tutoring Systems (2)
H. Chad Lane, Mike Schneider, Stephen W. Michael, Justin S. Albrechtsen, Christian A. Meissner
2010 conf
SLT
William R. Swartout, David R. Traum, Ron Artstein, Dan Noren, Paul E. Debevec, Kerry Bronnenkant, Josh Williams, Anton Leuski, Shrikanth S. Narayanan, Diane Piepol, H. Chad Lane, Jackie Morie, Priti Aggarwal, Matt Liewer, Jen-Yuan Chiang, Jillian Gerten, Selina Chu, Kyle White
2009 J jnl
Int. J. Artif. Intell. Educ.
Julia M. Kim, Randall W. Hill Jr., Paula J. Durlach, H. Chad Lane, Eric Forbell, Mark G. Core, Stacy Marsella, David V. Pynadath, John Hart
2009 A conf
AIED
Matthew J. Hays, H. Chad Lane, Daniel Auerbach, Mark G. Core, Dave Gomboc, Milton Rosenberg
2009 A conf
AIED
H. Chad Lane, Amy E. Ogan, Valerie J. Shute
2009 Misc ed.
FLAIRS
H. Chad Lane, Hans W. Guesgen
2009 conf
HCI (4)
H. Chad Lane
2009 A conf
AIED
Emmanuel G. Blanchard, H. Chad Lane, Daniele Allard
2008 Misc conf
FLAIRS
Dave Gomboc, Mark G. Core, H. Chad Lane, Ashish Karnavat, Milton Rosenberg
2008 Misc ed.
FLAIRS
David Wilson, H. Chad Lane
2007 A conf
AIED
Mark O. Riedl, Isabel Machado Alexandre, Brian Magerko, Ana Paiva, H. Chad Lane
2006 A* conf
AAAI
Mark G. Core, H. Chad Lane, Michael van Lent, Dave Gomboc, Steve Solomon, Milton Rosenberg
2006 B conf
Intelligent Tutoring Systems
H. Chad Lane, Mark G. Core, Dave Gomboc, Steve Solomon, Michael van Lent, Milton Rosenberg
2006 J jnl
Simul.
Mark G. Core, David R. Traum, H. Chad Lane, William R. Swartout, Jonathan Gratch, Michael van Lent, Stacy Marsella
2005 A conf
AIED
H. Chad Lane, Mark G. Core, Michael van Lent, Steve Solomon, Dave Gomboc
2005 A conf
SIGCSE
H. Chad Lane, Kurt VanLehn
2005 J jnl
Comput. Sci. Educ.
H. Chad Lane, Kurt VanLehn
2004 Misc conf
FLAIRS
H. Chad Lane, Kurt VanLehn
2003 A conf
SIGCSE
H. Chad Lane, Kurt VanLehn
redb/extractors/js_extractors/js_xray.py
← Index redb/extractors/js_extractors/js_xray.py python
"""Subprocess wrapper for the bundled js-x-ray Node bridge.

Mirrors `js_deobfuscator.py`: shell out to a Node script with a per-sample
timeout, kill the process group on hang, demote `FileNotFoundError` to debug
(missing tool is routine — the host either has Node + the bundled package
installed or it doesn't), and return a structured result on success.

The bridge lives at `redb/extractors/js_extractors/scripts/js-xray-runner.js`.
Operators install the JS dependency once with `npm install` in that directory
(or override the path with `JS_XRAY_RUNNER_PATH`).

Configuration (env vars):
    JS_XRAY_RUNNER_PATH   Path to the Node bridge script (default: bundled).
    JS_XRAY_TIMEOUT       Seconds before the subprocess is killed. Default: 30.

`run(source, log)` returns `XRayResult(obfuscator, warnings)` on a successful
analysis, or `XRayResult(None, [])` for any non-success path (binary missing,
timeout, parse failure, etc.). The two unsuccessful states are
indistinguishable to the caller on purpose — they all collapse to "no
js-x-ray verdict, fall back to heuristic".
"""

from __future__ import annotations

import json
import os
import signal
import subprocess
import tempfile
from dataclasses import dataclass, field
from typing import List, Optional

# Bundled bridge: redb/extractors/js_extractors/scripts/js-xray-runner.js
_DEFAULT_RUNNER = os.path.join(
    os.path.dirname(__file__), "scripts", "js-xray-runner.js"
)
_DEFAULT_NODE = "node"
_DEFAULT_TIMEOUT_SECS = 30


@dataclass
class XRayResult:
    """Parsed js-x-ray output. `obfuscator` is the recognised family name
    (e.g. "jsfuck", "obfuscator.io") or None when js-x-ray did not flag the
    code. `warnings` carries every {kind, value} pair the analyser produced;
    the heuristic uses it as a corroborating signal. `avg_identifier_length`
    is js-x-ray's own AST-derived figure — used as a fallback for the
    heuristic's `avg_identifier_length<2` strong signal when pyjsparser
    can't parse the source (anything ES2015+ trips it)."""

    obfuscator: Optional[str] = None
    warnings: List[dict] = field(default_factory=list)
    avg_identifier_length: Optional[float] = None

    @property
    def flagged(self) -> bool:
        return self.obfuscator is not None


def _empty() -> XRayResult:
    return XRayResult(obfuscator=None, warnings=[])


def run(source: str, log) -> XRayResult:
    if not source:
        return _empty()

    runner = os.getenv("JS_XRAY_RUNNER_PATH", _DEFAULT_RUNNER)
    node_bin = os.getenv("JS_XRAY_NODE_BIN", _DEFAULT_NODE)
    timeout = int(os.getenv("JS_XRAY_TIMEOUT", str(_DEFAULT_TIMEOUT_SECS)))

    if not os.path.exists(runner):
        log.debug(f"js-x-ray runner not found at {runner}")
        return _empty()

    # Skip the subprocess entirely when the JS dependency isn't installed.
    # Without this, every call to a host that has `node` but never ran
    # `npm install` next to the runner would still fork node, get a require
    # error, and exit nonzero — wasted ~50–200ms per JS sample (and per test).
    runner_dir = os.path.dirname(runner)
    if not os.path.isdir(os.path.join(runner_dir, "node_modules", "@nodesecure", "js-x-ray")):
        log.debug(f"@nodesecure/js-x-ray not installed in {runner_dir}")
        return _empty()

    tmp_path = None
    try:
        with tempfile.NamedTemporaryFile(
            suffix=".js", mode="w", delete=False, encoding="utf-8"
        ) as tmp:
            tmp.write(source)
            tmp_path = tmp.name

        try:
            process = subprocess.Popen(
                [node_bin, runner, tmp_path],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                preexec_fn=os.setsid,
            )
            try:
                stdout, stderr = process.communicate(timeout=timeout)
            except subprocess.TimeoutExpired:
                # Kill the whole process group so any node helpers die too.
                try:
                    os.killpg(os.getpgid(process.pid), signal.SIGTERM)
                    process.wait(timeout=5)
                except Exception:
                    try:
                        os.killpg(os.getpgid(process.pid), signal.SIGKILL)
                    except Exception:
                        pass
                log.warning(f"js-x-ray timed out after {timeout}s")
                return _empty()

            if process.returncode != 0:
                err = stderr.decode("utf-8", errors="replace").strip()
                log.debug(f"js-x-ray exited {process.returncode}: {err}")
                return _empty()

            text = stdout.decode("utf-8", errors="replace").strip()
            if not text:
                return _empty()

            try:
                payload = json.loads(text)
            except json.JSONDecodeError as e:
                log.warning(f"js-x-ray emitted non-JSON output: {e}")
                return _empty()

            obfuscator = payload.get("obfuscator")
            warnings = payload.get("warnings") or []
            if not isinstance(warnings, list):
                warnings = []

            ids_avg = payload.get("idsLengthAvg")
            if not isinstance(ids_avg, (int, float)):
                ids_avg = None

            return XRayResult(
                obfuscator=obfuscator,
                warnings=warnings,
                avg_identifier_length=ids_avg,
            )
        finally:
            if tmp_path:
                try:
                    os.unlink(tmp_path)
                except Exception:
                    pass
    except FileNotFoundError:
        log.debug(f"node binary not found at {node_bin}")
        return _empty()
    except Exception as e:
        log.error(f"js-x-ray subprocess error: {e}")
        return _empty()