Full Code of sk89q/WarmRoast for AI

master d814c4f03915 cached
14 files
43.7 KB
11.1k tokens
58 symbols
1 requests
Download .txt
Repository: sk89q/WarmRoast
Branch: master
Commit: d814c4f03915
Files: 14
Total size: 43.7 KB

Directory structure:
gitextract_dl1f2tde/

├── .github/
│   └── workflows/
│       └── build.yml
├── .gitignore
├── README.md
├── pom.xml
└── src/
    └── main/
        ├── java/
        │   └── com/
        │       └── sk89q/
        │           └── warmroast/
        │               ├── ClassMapping.java
        │               ├── DataViewServlet.java
        │               ├── McpMapping.java
        │               ├── RoastOptions.java
        │               ├── StackNode.java
        │               ├── StackTraceNode.java
        │               └── WarmRoast.java
        └── resources/
            └── www/
                ├── index.html
                ├── style.css
                └── warmroast.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/build.yml
================================================
name: Build

on:
  - push
  - pull_request

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
      name: Checkout repo

    - name: Set up JDK 17 (LTS)
      uses: actions/setup-java@v2
      with:
        java-version: '17'
        distribution: 'adopt'
        cache: maven

    - name: Build with Maven
      run: mvn install

    - uses: actions/upload-artifact@v2
      name: Upload Artifact
      with:
        name: WarmRoast
        path: target/warmroast-*.jar

================================================
FILE: .gitignore
================================================
# Eclipse stuff
/.classpath
/.project
/.settings

# netbeans
/nbproject

# we use maven!
/build.xml

# maven
/target

# vim
.*.sw[a-p]

# various other potential build files
/build
/bin
/dist
/manifest.mf
/dependency-reduced-pom.xml

# Mac filesystem dust
/.DS_Store

# intellij
*.iml
*.ipr
*.iws
.idea/

================================================
FILE: README.md
================================================
WarmRoast
=========

*Note: This project is not actively maintained but should work. (2024)*

WarmRoast attaches to Minecraft (or any Java application) and lets you see what it's doing. While what it's doing can be cryptic, with some practice, you can start to figure out patterns.

* Adjustable sampling frequency.
* Supports loading MCP mappings for deobfuscating class and method names.
* Web-based — perform the profiling on a remote server and view the results in your browser.
 * Collapse and expand nodes to see details.
 * Easily view CPU usage per method at a glance.
 * Hover to highlight all child methods as a group.
 * See the percentage of CPU time for each method relative to its parent methods.
 * Maintains style and function with use of "File -> Save As" (in tested browsers).

### Download

**Latest Release**: [here](../../releases)

**Latest Build**: [here](../../actions/workflows/build.yml)

Screenshots
-----------

![Sample output](http://i.imgur.com/Iy7kJ7f.png)

Usage
-----

Extract the .zip file and place the .jar somewhere.

### For Java 9 and newer ### 

The `tools.jar` is automatically included into JDK's since Java 9. You only should use something like this:

    java -cp warmroast-1.0.0-SNAPSHOT.jar com.sk89q.warmroast.WarmRoast --thread "Server thread"

### For Java 7 & 8 ### 

1. Note the path of your JDK.

2. Download WarmRoast.

3. Replace `PATH_TO_JDK` in the following commands with the path to your JDK and execute the program.

**Note:** The example command line below includes `--thread "Server thread"`, which filters all threads but the main server thread. You can remove it to show all threads.

**Modded/vanilla servers:** If you are using a modded server, get a copy of [MCP](http://mcp.ocean-labs.de/index.php/MCP_Releases) for your server's Minecraft version, copy the files from conf/ somewhere, and point WarmRoast to it with `--mappings path/to/folder`. This helps readability a lot. Bukkit uses its own mapping, so a pure non-modded Bukkit server can't use MCP mappings.

#### Linux ####

    java -Djava.library.path=PATH_TO_JDK/jre/bin -cp PATH_TO_JDK/lib/tools.jar:warmroast-1.0.0-SNAPSHOT.jar com.sk89q.warmroast.WarmRoast --thread "Server thread"

#### Windows ####

An example `PATH_TO_JDK` would be `C:\Program Files\Java\jdk1.7.0_45`

    java -Djava.library.path=PATH_TO_JDK/jre/bin -cp PATH_TO_JDK/lib/tools.jar;warmroast-1.0.0-SNAPSHOT.jar com.sk89q.warmroast.WarmRoast --thread "Server thread"

* The folder `PATH_TO_JDK/jre/bin` should contain "attach.dll"
* The folder `PATH_TO_JDK/lib` should contain "tools.jar"

Parameters
----------

    Usage: warmroast [options]
      Options:
        --bind
           The address to bind the HTTP server to
           Default: 0.0.0.0
           
        -h, --help
           Default: false
           
        --interval
           The sample rate, in milliseconds
           Default: 100
           
        -m, --mappings
           A directory with joined.srg and methods.csv
           
        --name
           The name of the VM to attach to
           
        --pid
           The PID of the VM to attach to
           
        -p, --port
           The port to bind the HTTP server to
           Default: 23000
           
        -t, --thread
           Optionally specify a thread to log only
           
        --timeout
           The number of seconds before ceasing sampling (optional)

Hint: `--thread "Server thread"` is useful for Minecraft servers.

License
-------

The project is licensed under the GNU General Public License, version 3.


================================================
FILE: pom.xml
================================================
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.sk89q</groupId>
  <artifactId>warmroast</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <name>WarmRoast</name>
  <url>http://www.sk89q.com</url>

  <scm>
    <connection>scm:git:git://github.com/sk89q/warmroast.git</connection>
    <url>https://github.com/sk89q/warmroast</url>
    <developerConnection>scm:git:git@github.com:sk89q/warmroast.git</developerConnection>
  </scm>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <distributionManagement>
    <site>
      <id>sk89q-docs-upload</id>
      <url>ftp://sk89q-maven-deploy/worldedit/</url>
    </site>
    <repository>
        <id>maven.sk89q.com</id>
        <url>http://maven.sk89q.com/artifactory/libs-release-local</url>
    </repository>
    <snapshotRepository>
        <id>maven.sk89q.com-snapshot</id>
        <url>http://maven.sk89q.com/artifactory/libs-snapshot-local</url>
    </snapshotRepository>
  </distributionManagement>
  <dependencies>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-servlet</artifactId>
      <version>9.0.3.v20130506</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
    <dependency>
      <groupId>net.sf.opencsv</groupId>
      <artifactId>opencsv</artifactId>
      <version>2.0</version>
    </dependency>
    <dependency>
      <groupId>com.beust</groupId>
      <artifactId>jcommander</artifactId>
      <version>1.30</version>
    </dependency>
  </dependencies>
  <build>
    <resources>
      <resource>
        <targetPath>www</targetPath>
        <filtering>false</filtering>
        <directory>${basedir}/src/main/resources/www</directory>
        <includes>
          <include>**/*</include>
        </includes>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.0</version>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>com.sk89q.warmroast.WarmRoast</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <filters>
                <filter>
                  <artifact>*:*</artifact>
                  <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                  </excludes>
                </filter>
              </filters>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>


================================================
FILE: src/main/java/com/sk89q/warmroast/ClassMapping.java
================================================
/*
 * WarmRoast
 * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.warmroast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ClassMapping {
    
    private final String obfuscated;
    private final String actual;
    private final Map<String, List<String>> methods = new HashMap<>();
    
    public ClassMapping(String obfuscated, String actual) {
        this.obfuscated = obfuscated;
        this.actual = actual;
    }

    public String getObfuscated() {
        return obfuscated;
    }
    
    public String getActual() {
        return actual;
    }
    
    public void addMethod(String obfuscated, String actual) {
        List<String> m = methods.get(obfuscated);
        if (m == null) {
            m = new ArrayList<>();
            methods.put(obfuscated, m);
        }
        m.add(actual);
    }
    
    public List<String> mapMethod(String obfuscated) {
        List<String> m = methods.get(obfuscated);
        if (m == null) {
            return new ArrayList<>();
        }
        return m;
    }
    
    @Override
    public String toString() {
        return getObfuscated() + "->" + getActual();
    }

}


================================================
FILE: src/main/java/com/sk89q/warmroast/DataViewServlet.java
================================================
/*
 * WarmRoast
 * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.warmroast;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DataViewServlet extends HttpServlet {
    
    private static final long serialVersionUID = -2331397310804298286L;
    
    private final WarmRoast roast;

    public DataViewServlet(WarmRoast roast) {
        this.roast = roast;
    }

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html; charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        
        PrintWriter w = response.getWriter();
        w.println("<!DOCTYPE html><html><head><title>WarmRoast</title>");
        w.println("<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">");
        w.println("</head><body>");
        w.println("<h1>WarmRoast</h1>");
        w.println("<div class=\"loading\">Downloading snapshot; please wait...</div>");
        w.println("<div class=\"stack\" style=\"display: none\">");
        synchronized (roast) {
            Collection<StackNode> nodes = roast.getData().values();
            for (StackNode node : nodes) {
                w.println(node.toHtml(roast.getMapping()));
            }
            if (nodes.size() == 0) {
                w.println("<p class=\"no-results\">There are no results. " +
                		"(Thread filter does not match thread?)</p>");
            }
        }
        w.println("</div>");
        w.println("<p class=\"legend\">Legend: ");
        w.println("<span class=\"matched\">Mapped</span> ");
        w.println("<span class=\"multiple-matches\">Multiple Mappings</span> ");
        w.println("</p>");
        w.println("<div id=\"overlay\"></div>");
        w.println("<p class=\"footer\">");
        w.println("Icons from <a href=\"http://www.fatcow.com/\">FatCow</a> &mdash; ");
        w.println("<a href=\"http://github.com/sk89q/warmroast\">github.com/sk89q/warmroast</a></p>");
        w.println("<script src=\"//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js\"></script>");
        w.println("<script src=\"warmroast.js\"></script>");
        w.println("</body></html>");
    }
}

================================================
FILE: src/main/java/com/sk89q/warmroast/McpMapping.java
================================================
/*
 * WarmRoast
 * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.warmroast;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;

import au.com.bytecode.opencsv.CSVReader;

public class McpMapping {

    private static final Pattern clPattern = 
            Pattern.compile("CL: (?<obfuscated>[^ ]+) (?<actual>[^ ]+)");
    private static final Pattern mdPattern = 
            Pattern.compile("MD: (?<obfuscatedClass>[^ /]+)/(?<obfuscatedMethod>[^ ]+) " +
            		"[^ ]+ (?<method>[^ ]+) [^ ]+");

    private final Map<String, ClassMapping> classes = new HashMap<>();
    private final Map<String, String> methods = new HashMap<>();
    
    public ClassMapping mapClass(String obfuscated) {
        return classes.get(obfuscated);
    }

    public void read(File joinedFile, File methodsFile) throws IOException {
        try (FileReader r = new FileReader(methodsFile)) {
            try (CSVReader reader = new CSVReader(r)) {
                List<String[]> entries = reader.readAll();
                processMethodNames(entries);
            }
        }
        
        List<String> lines = FileUtils.readLines(joinedFile, "UTF-8");
        processClasses(lines);
        processMethods(lines);
    }
    
    public String mapMethodId(String id) {
        return methods.get(id);
    }
    
    public String fromMethodId(String id) {
        String method = methods.get(id);
        if (method == null) {
            return id;
        }
        return method;
    }
    
    private void processMethodNames(List<String[]> entries) {
        boolean first = true;
        for (String[] entry : entries) {
            if (entry.length < 2) {
                continue;
            }
            if (first) { // Header
                first = false;
                continue;
            }
            methods.put(entry[0], entry[1]);
        }
    }
    
    private void processClasses(List<String> lines) {
        for (String line : lines) {
            Matcher m = clPattern.matcher(line);
            if (m.matches()) {
                String obfuscated = m.group("obfuscated");
                String actual = m.group("actual").replace("/", ".");
                classes.put(obfuscated, new ClassMapping(obfuscated, actual));
            }
        }
    }
    
    private void processMethods(List<String> lines) {
        for (String line : lines) {
            Matcher m = mdPattern.matcher(line);
            if (m.matches()) {
                String obfuscatedClass = m.group("obfuscatedClass");
                String obfuscatedMethod = m.group("obfuscatedMethod");
                String method = m.group("method");
                String methodId = method.substring(method.lastIndexOf('/') + 1);
                ClassMapping mapping = mapClass(obfuscatedClass);
                if (mapping != null) {
                    mapping.addMethod(obfuscatedMethod, 
                            fromMethodId(methodId));
                }
            }
        }
    }

}


================================================
FILE: src/main/java/com/sk89q/warmroast/RoastOptions.java
================================================
/*
 * WarmRoast
 * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package com.sk89q.warmroast;

import com.beust.jcommander.Parameter;

public class RoastOptions {
    
    @Parameter(names = { "-h", "--help" }, help = true)
    public boolean help;

    @Parameter(names = { "--bind" }, description = "The address to bind the HTTP server to")
    public String bindAddress = "0.0.0.0";

    @Parameter(names = { "-p", "--port" }, description = "The port to bind the HTTP server to")
    public Integer port = 23000;

    @Parameter(names = { "--pid" }, description = "The PID of the VM to attach to")
    public Integer pid;

    @Parameter(names = { "--name" }, description = "The name of the VM to attach to")
    public String vmName;

    @Parameter(names = { "-t", "--thread" }, description = "Optionally specify a thread to log only")
    public String threadName;

    @Parameter(names = { "-m", "--mappings" }, description = "A directory with joined.srg and methods.csv")
    public String mappingsDir;

    @Parameter(names = { "--interval" }, description = "The sample rate, in milliseconds")
    public Integer interval = 100;
    
    @Parameter(names = { "--timeout" }, description = "The number of seconds before ceasing sampling (optional)")
    public Integer timeout;

}


================================================
FILE: src/main/java/com/sk89q/warmroast/StackNode.java
================================================
/*
 * WarmRoast
 * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.warmroast;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class StackNode implements Comparable<StackNode> {
    
    private static final NumberFormat cssDec = NumberFormat.getPercentInstance(Locale.US);
    private final String name;
    private final Map<String, StackNode> children = new HashMap<>();
    private long totalTime;
    
    static {
        cssDec.setGroupingUsed(false);
        cssDec.setMaximumFractionDigits(2);
    }

    public StackNode(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    public String getNameHtml(McpMapping mapping) {
        return escapeHtml(getName());
    }

    public Collection<StackNode> getChildren() {
        List<StackNode> list = new ArrayList<>(children.values());
        Collections.sort(list);
        return list;
    }
    
    public StackNode getChild(String name) {
        StackNode child = children.get(name);
        if (child == null) {
            child = new StackNode(name);
            children.put(name, child);
        }
        return child;
    }
    
    public StackNode getChild(String className, String methodName) {
        StackTraceNode node = new StackTraceNode(className, methodName);
        StackNode child = children.get(node.getName());
        if (child == null) {
            child = node;
            children.put(node.getName(), node);
        }
        return child;
    }
    
    public long getTotalTime() {
        return totalTime;
    }

    public void log(long time) {
        totalTime += time;
    }
    
    private void log(StackTraceElement[] elements, int skip, long time) {
        log(time);
        
        if (elements.length - skip == 0) {
            return;
        }
        
        StackTraceElement bottom = elements[elements.length - (skip + 1)];
        getChild(bottom.getClassName(), bottom.getMethodName())
                .log(elements, skip + 1, time);
    }
    
    public void log(StackTraceElement[] elements, long time) {
        log(elements, 0, time);
    }

    @Override
    public int compareTo(StackNode o) {
        return getName().compareTo(o.getName());
    }
    
    private void writeHtml(StringBuilder builder, McpMapping mapping, long totalTime) {
        builder.append("<div class=\"node collapsed\">");
        builder.append("<div class=\"name\">");
        builder.append(getNameHtml(mapping));
        builder.append("<span class=\"percent\">");
        builder
                .append(String.format("%.2f", getTotalTime() / (double) totalTime * 100))
                .append("%");
        builder.append("</span>");
        builder.append("<span class=\"time\">");
        builder.append(getTotalTime()).append("ms");
        builder.append("</span>");
        builder.append("<span class=\"bar\">");
        builder.append("<span class=\"bar-inner\" style=\"width:")
                .append(formatCssPct(getTotalTime() / (double) totalTime))
                .append("\">");
        builder.append("</span>");
        builder.append("</span>");
        builder.append("</div>");
        builder.append("<ul class=\"children\">");
        for (StackNode child : getChildren()) {
            builder.append("<li>");
            child.writeHtml(builder, mapping, totalTime);
            builder.append("</li>");
        }
        builder.append("</ul>");
        builder.append("</div>");
    }

    public String toHtml(McpMapping mapping) {
        StringBuilder builder = new StringBuilder();
        writeHtml(builder, mapping, getTotalTime());
        return builder.toString();
    }
    
    private void writeString(StringBuilder builder, int indent) {
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < indent; i++) {
            b.append(" ");
        }
        String padding = b.toString();
        
        for (StackNode child : getChildren()) {
            builder.append(padding).append(child.getName());
            builder.append(" ");
            builder.append(getTotalTime()).append("ms");
            builder.append("\n");
            child.writeString(builder, indent + 1);
        }
    }
    
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        writeString(builder, 0);
        return builder.toString();
    }
    
    protected static String formatCssPct(double pct) {
        return cssDec.format(pct);
    }
    
    protected static String escapeHtml(String str) {
        return str.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
    }

}


================================================
FILE: src/main/java/com/sk89q/warmroast/StackTraceNode.java
================================================
/*
 * WarmRoast
 * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.warmroast;

import java.util.List;

public class StackTraceNode extends StackNode {
    
    private final String className;
    private final String methodName;

    public StackTraceNode(String className, String methodName) {
        super(className + "." + methodName + "()");
        this.className = className;
        this.methodName = methodName;
    }

    public String getClassName() {
        return className;
    }

    public String getMethodName() {
        return methodName;
    }
    
    @Override
    public String getNameHtml(McpMapping mapping) {
        ClassMapping classMapping = mapping.mapClass(getClassName());
        if (classMapping != null) {
            String className = "<span class=\"matched\" title=\"" + 
                    escapeHtml(getClassName()) + "\">" +
                    escapeHtml(classMapping.getActual()) + "</span>";
            
            List<String> actualMethods = classMapping.mapMethod(getMethodName());
            if (actualMethods.size() == 0) {
                return className + "." + escapeHtml(getMethodName()) + "()";
            } else if (actualMethods.size() == 1) {
                return className + 
                        ".<span class=\"matched\" title=\"" + 
                        escapeHtml(getMethodName()) + "\">" + 
                        escapeHtml(actualMethods.get(0)) + "</span>()";
            } else {
                StringBuilder builder = new StringBuilder();
                boolean first = true;
                for (String m : actualMethods) {
                    if (!first) {
                        builder.append(" ");
                    }
                    builder.append(m);
                    first = false;
                }
                return className + 
                        ".<span class=\"multiple-matches\" title=\"" + 
                            builder.toString() + "\">" + escapeHtml(getMethodName()) + "</span>()";
            }
        } else {
            String actualMethod = mapping.mapMethodId(getMethodName());
            if (actualMethod == null) {
                return escapeHtml(getClassName()) + "." + escapeHtml(getMethodName()) + "()";
            } else {
                return className + 
                        ".<span class=\"matched\" title=\"" + 
                        escapeHtml(getMethodName()) + "\">" + 
                        escapeHtml(actualMethod) + "</span>()";
            }
        }
    }

    @Override
    public int compareTo(StackNode o) {
        if (getTotalTime() == o.getTotalTime()) {
            return 0;
        } else if (getTotalTime()> o.getTotalTime()) {
            return -1;
        } else {
            return 1;
        }
    }

}


================================================
FILE: src/main/java/com/sk89q/warmroast/WarmRoast.java
================================================
/*
 * WarmRoast
 * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.warmroast;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;

import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import com.beust.jcommander.JCommander;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;

public class WarmRoast extends TimerTask {

    private static final String SEPARATOR = 
            "------------------------------------------------------------------------";
    
    private final int interval;
    private final VirtualMachine vm;
    private final Timer timer = new Timer("Roast Pan", true);
    private final McpMapping mapping = new McpMapping();
    private final SortedMap<String, StackNode> nodes = new TreeMap<>();
    private JMXConnector connector;
    private MBeanServerConnection mbsc;
    private ThreadMXBean threadBean;
    private String filterThread;
    private long endTime = -1;
    
    public WarmRoast(VirtualMachine vm, int interval) {
        this.vm = vm;
        this.interval = interval;
    }
    
    public Map<String, StackNode> getData() {
        return nodes;
    }
    
    private StackNode getNode(String name) {
        StackNode node = nodes.get(name);
        if (node == null) {
            node = new StackNode(name);
            nodes.put(name, node);
        }
        return node;
    }
    
    public McpMapping getMapping() {
        return mapping;
    }
    
    public String getFilterThread() {
        return filterThread;
    }

    public void setFilterThread(String filterThread) {
        this.filterThread = filterThread;
    }

    public long getEndTime() {
        return endTime;
    }

    public void setEndTime(long l) {
        this.endTime = l;
    }

    public void connect() 
            throws IOException, AgentLoadException, AgentInitializationException {
        // Load the agent
        String connectorAddr = vm.getAgentProperties().getProperty(
                "com.sun.management.jmxremote.localConnectorAddress");
        if (connectorAddr == null) {
            String agent = vm.getSystemProperties().getProperty("java.home")
                    + File.separator + "lib" + File.separator
                    + "management-agent.jar";
            vm.loadAgent(agent);
            connectorAddr = vm.getAgentProperties().getProperty(
                    "com.sun.management.jmxremote.localConnectorAddress");
        }

        // Connect
        JMXServiceURL serviceURL = new JMXServiceURL(connectorAddr);
        connector = JMXConnectorFactory.connect(serviceURL);
        mbsc = connector.getMBeanServerConnection();
        try {
            threadBean = getThreadMXBean();
        } catch (MalformedObjectNameException e) {
            throw new IOException("Bad MX bean name", e);
        }
    }

    private ThreadMXBean getThreadMXBean() 
            throws IOException, MalformedObjectNameException {
        ObjectName objName = new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME);
        Set<ObjectName> mbeans = mbsc.queryNames(objName, null);
        for (ObjectName name : mbeans) {
            return ManagementFactory.newPlatformMXBeanProxy(
                    mbsc, name.toString(), ThreadMXBean.class);
        }
        throw new IOException("No thread MX bean found");
    }

    @Override
    public synchronized void run() {
        if (endTime >= 0) {
            if (endTime <= System.currentTimeMillis()) {
                cancel();
                System.err.println("Sampling has stopped.");
                return;
            }
        }
        
        ThreadInfo[] threadDumps = threadBean.dumpAllThreads(false, false);
        for (ThreadInfo threadInfo : threadDumps) {
            String threadName = threadInfo.getThreadName();
            StackTraceElement[] stack = threadInfo.getStackTrace();
            
            if (threadName == null || stack == null) {
                continue;
            }
            
            if (filterThread != null && !filterThread.equals(threadName)) {
                continue;
            }
            
            StackNode node = getNode(threadName);
            node.log(stack, interval);
        }
    }

    public void start(InetSocketAddress address) throws Exception {
        timer.scheduleAtFixedRate(this, interval, interval);
        
        Server server = new Server(address);

        ServletContextHandler context = new ServletContextHandler();
        context.setContextPath("/");
        context.addServlet(new ServletHolder(new DataViewServlet(this)), "/stack");

        ResourceHandler resources = new ResourceHandler();
        String filesDir = WarmRoast.class.getResource("/www").toExternalForm();
        resources.setResourceBase(filesDir);
        resources.setDirectoriesListed(true);
        resources.setWelcomeFiles(new String[]{ "index.html" });
 
        HandlerList handlers = new HandlerList();
        handlers.addHandler(context);
        handlers.addHandler(resources);
        server.setHandler(handlers);

        server.start();
        server.join();
    }

    public static void main(String[] args) throws AgentLoadException {
        RoastOptions opt = new RoastOptions();
        JCommander jc = new JCommander(opt, args);
        jc.setProgramName("warmroast");
        
        if (opt.help) {
            jc.usage();
            System.exit(0);
        }

        System.err.println(SEPARATOR);
        System.err.println("WarmRoast");
        System.err.println("http://github.com/sk89q/warmroast");
        System.err.println(SEPARATOR);
        System.err.println("");
        
        VirtualMachine vm = null;
        
        if (opt.pid != null) {
            try {
                vm = VirtualMachine.attach(String.valueOf(opt.pid));
                System.err.println("Attaching to PID " + opt.pid + "...");
            } catch (AttachNotSupportedException | IOException e) {
                System.err.println("Failed to attach VM by PID " + opt.pid);
                e.printStackTrace();
                System.exit(1);
            }
        } else if (opt.vmName != null) {
            for (VirtualMachineDescriptor desc : VirtualMachine.list()) {
                if (desc.displayName().contains(opt.vmName)) {
                    try {
                        vm = VirtualMachine.attach(desc);
                        System.err.println("Attaching to '" + desc.displayName() + "'...");
                        
                        break;
                    } catch (AttachNotSupportedException | IOException e) {
                        System.err.println("Failed to attach VM by name '" + opt.vmName + "'");
                        e.printStackTrace();
                        System.exit(1);
                    }
                }
            }
        }
        
        if (vm == null) {
            List<VirtualMachineDescriptor> descriptors = VirtualMachine.list();
            System.err.println("Choose a VM:");
            
            Collections.sort(descriptors, new Comparator<VirtualMachineDescriptor>() {
                @Override
                public int compare(VirtualMachineDescriptor o1,
                        VirtualMachineDescriptor o2) {
                    return o1.displayName().compareTo(o2.displayName());
                }
            });
            
            // Print list of VMs
            int i = 1;
            for (VirtualMachineDescriptor desc : descriptors) {
                System.err.println("[" + (i++) + "] " + desc.displayName());
            }
            
            // Ask for choice
            System.err.println("");
            System.err.print("Enter choice #: ");
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String s;
            try {
                s = reader.readLine();
            } catch (IOException e) {
                return;
            }
            
            // Get the VM
            try {
                int choice = Integer.parseInt(s) - 1;
                if (choice < 0 || choice >= descriptors.size()) {
                    System.err.println("");
                    System.err.println("Given choice is out of range.");
                    System.exit(1);
                }
                vm = VirtualMachine.attach(descriptors.get(choice));
            } catch (NumberFormatException e) {
                System.err.println("");
                System.err.println("That's not a number. Bye.");
                System.exit(1);
            } catch (AttachNotSupportedException | IOException e) {
                System.err.println("");
                System.err.println("Failed to attach VM");
                e.printStackTrace();
                System.exit(1);
            }
        }
        
        InetSocketAddress address = new InetSocketAddress(opt.bindAddress, opt.port);

        WarmRoast roast = new WarmRoast(vm, opt.interval);
        if (opt.mappingsDir != null) {
            File dir = new File(opt.mappingsDir);
            File joined = new File(dir, "joined.srg");
            File methods = new File(dir, "methods.csv");
            try {
                roast.getMapping().read(joined, methods);
            } catch (IOException e) {
                System.err.println(
                        "Failed to read the mappings files (joined.srg, methods.csv) " +
                        "from " + dir.getAbsolutePath() + ": " + e.getMessage());
                System.exit(2);
            }
        }

        System.err.println(SEPARATOR);
        
        roast.setFilterThread(opt.threadName);
        
        if (opt.timeout != null && opt.timeout > 0) {
            roast.setEndTime(System.currentTimeMillis() + opt.timeout * 1000);
            System.err.println("Sampling set to stop in " + opt.timeout + " seconds.");
        }

        System.err.println("Starting a server on " + address.toString() + "...");
        System.err.println("Once the server starts (shortly), visit the URL in your browser.");
        System.err.println("Note: The longer you wait before using the output of that " +
        		"webpage, the more accurate the results will be.");
        
        try {
            roast.connect();
            roast.start(address);
        } catch (Throwable t) {
            t.printStackTrace();
            System.exit(3);
        }
    }

}


================================================
FILE: src/main/resources/www/index.html
================================================
<!DOCTYPE html><html><head><title>WarmRoast</title>
<style>@import url(style.css);</style>
</head><body>
<h1>WarmRoast</h1>

<p>
    <a href="/stack">View sampler results</a>
</p>

<p class="footer">
<a href="http://github.com/sk89q/warmroast">github.com/sk89q/warmroast</a></p>

</body></html>


================================================
FILE: src/main/resources/www/style.css
================================================
@import url(http://fonts.googleapis.com/css?family=Lato);

body {
    font-family: 'Lato', Arial, sans-serif;
    font-size: 10pt;
    line-height: 150%;
    margin: 0;
    padding: 54px 20px 20px 20px;
}

ul {
    margin: 0;
    padding: 0 0 0 18px;
}

li {
    margin: 0;
    margin-left: -10px;
    padding: 0;
    list-style: none;
    border-left: 1px solid #ccc;
}

a:link, a:visited {
    color: #FF3213;
    text-decoration: none;
    border-bottom: 1px solid #CCC;
}

a:hover, a:active {
    color: #000;
    border-color: black;
    text-decoration: none;
}

.stack {
    margin-left: 60px;
}

.name {
    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA10lEQVR4Xt2Tu8rCQBSEzzlJmYBvYJ7EShArfQ1BrPNDyoB5DRHsrUQQQc3lcfxBiKbIHjfiCuayKSwEB6ZYPpjdGVhkZvhEJP3dALMMgmB+FoI7ddUQEYhw7bp/48YAkYtOfzCEJu22m5G2gnjeHIYxxHGiXJwV11dQTzdN4w0QKa4JULplGcymkwo4Rkn7iCjNOcNiuVK3vQZ0ug5gWwAgPnpalgW1+yDqA4hQmmSADVVGBW8bES7RaW+zYOBSNSSENL0etAGe5/UkMKBZ/77vv8APfKY7cvZVTt7VqzwAAAAASUVORK5CYII=) center left no-repeat;
    padding-left: 20px;
    cursor: pointer;
}

.name:hover {
    background-color: #CCC;
}

.name:hover + ul {
    background: #EFEFEF;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
    border-radius: 3px;
}

.matched {
    background: #CCC;
    border-radius: 3px;
    padding: 0 4px;
}

.multiple-matches {
    background: #FF3213;
    color: #FFF;
    padding: 0 4px;
    border-radius: 3px;
}

.matched:hover, .multiple-matches:hover {
    background: #000000;
    color: #FFF;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
}

.percent {
    color: #6b98ff;
    font-size: 90%;
    border-radius: 3px;
    padding: 0 4px;
}

.bar {
    display: inline-block;
    width: 100px;
    height: 15px;
    margin-left: 20px;
    border: 1px solid #CCC;
    position: absolute;
    right: 30px;
    background: #FFF;
}

.bar-inner {
    display: inline-block;
    height: 16px;
    background: #6b98ff;
}

#overlay span {
    position: absolute;
    color: #6b98ff;
    font-size: 90%;
    z-index: 10;
    line-height: 150%;
    left: 20px;
    width: 50px;
    text-align: right;
}

.time {
    display: none;
    margin: 0;
    color: #888;
    font-size: 90%;
    border-radius: 3px;
    padding: 0 4px;
}

.name:hover .time {
    display: inline;
}

ul {
    display: none;
}

.collapsed > .name {
    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA7ElEQVR4Xt1TzYrCQAxOYo8z0GeRZY+eBPGkryGIZ4UeC/Yx/EHvnqTssot/9XF2YUHXQyd2RtuC2OnBg2AgJF/CfJkvwyAzwyNGiT+XwLktBMHwRyl270lDRCDCRb8/aBcSqFi59UYTiuwzXLasEtR18nYbQRTt4f2tqqPGad8uIb2641TyKUSJp307gbH/0wl63U4Ks3y925e/AibOMcN4OofRZKZLOmps6lj2CoBodAohspKUMtePaCcgQqNZCGlw+PFt8nwXWLZE+NttviQrBr6RhoRwOBxXVgLP82pJqECx/fq+n4EX+ExnBI9csQQ1hIoAAAAASUVORK5CYII=);
}

h1 {
    background: #FFF;
    color: #111;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    padding: 10px 20px;
    margin: 0;
    font-size: 14pt;
    font-weight: normal;
    box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
    z-index: 20;
}

.footer {
    background: #FFF;
    color: #333;
    margin: 100px 0 0 0;
    font-size: 10pt;
    font-weight: normal;
    text-align: right;
}

.loading {
    font-size: 130%;
    background: #EFEFEF;
    border: 1px solid #CCC;
    padding: 8px;
    border-radius: 3px;
}

.no-results {
    font-size: 130%;
    color: #800000;
}

================================================
FILE: src/main/resources/www/warmroast.js
================================================
$(".name").on("click", function(event) {
    var $parent = $(this).parent();
    if ($parent.hasClass("collapsed")) {
        $parent.removeClass("collapsed");
        $parent.children("ul").slideDown(50);
    } else {
        $parent.addClass("collapsed");
        $parent.children("ul").slideUp(50);
    }
});

function extractTime($el) {
    var text = $el.children(".name")
        .children(".time").text().replace(/[^0-9]/, "");
    return parseInt(text);
}

var $overlay = $("#overlay");

$(".name").on("mouseenter", function(event) {
    var $this = $(this);
    var thisTime = null;
    $overlay.empty();
    $this.parents(".node").each(function(i, parent) {
        var $parent = $(parent);
        var time = extractTime($parent);
        if (thisTime == null) {
            thisTime = time;
        } else {
            var $el = $(document.createElement("span"));
            var pos = $parent.position();
            var width = $el.outerWidth();
            $el.text(((thisTime / time) * 100).toFixed(2) + "%");
            $el.css({
                top: pos.top + "px"
            });
            $overlay.append($el);
        }
    });
});

$(".loading").hide();
$(".stack").show();
Download .txt
gitextract_dl1f2tde/

├── .github/
│   └── workflows/
│       └── build.yml
├── .gitignore
├── README.md
├── pom.xml
└── src/
    └── main/
        ├── java/
        │   └── com/
        │       └── sk89q/
        │           └── warmroast/
        │               ├── ClassMapping.java
        │               ├── DataViewServlet.java
        │               ├── McpMapping.java
        │               ├── RoastOptions.java
        │               ├── StackNode.java
        │               ├── StackTraceNode.java
        │               └── WarmRoast.java
        └── resources/
            └── www/
                ├── index.html
                ├── style.css
                └── warmroast.js
Download .txt
SYMBOL INDEX (58 symbols across 8 files)

FILE: src/main/java/com/sk89q/warmroast/ClassMapping.java
  class ClassMapping (line 26) | public class ClassMapping {
    method ClassMapping (line 32) | public ClassMapping(String obfuscated, String actual) {
    method getObfuscated (line 37) | public String getObfuscated() {
    method getActual (line 41) | public String getActual() {
    method addMethod (line 45) | public void addMethod(String obfuscated, String actual) {
    method mapMethod (line 54) | public List<String> mapMethod(String obfuscated) {
    method toString (line 62) | @Override

FILE: src/main/java/com/sk89q/warmroast/DataViewServlet.java
  class DataViewServlet (line 30) | public class DataViewServlet extends HttpServlet {
    method DataViewServlet (line 36) | public DataViewServlet(WarmRoast roast) {
    method doGet (line 40) | @Override

FILE: src/main/java/com/sk89q/warmroast/McpMapping.java
  class McpMapping (line 34) | public class McpMapping {
    method mapClass (line 45) | public ClassMapping mapClass(String obfuscated) {
    method read (line 49) | public void read(File joinedFile, File methodsFile) throws IOException {
    method mapMethodId (line 62) | public String mapMethodId(String id) {
    method fromMethodId (line 66) | public String fromMethodId(String id) {
    method processMethodNames (line 74) | private void processMethodNames(List<String[]> entries) {
    method processClasses (line 88) | private void processClasses(List<String> lines) {
    method processMethods (line 99) | private void processMethods(List<String> lines) {

FILE: src/main/java/com/sk89q/warmroast/RoastOptions.java
  class RoastOptions (line 23) | public class RoastOptions {

FILE: src/main/java/com/sk89q/warmroast/StackNode.java
  class StackNode (line 30) | public class StackNode implements Comparable<StackNode> {
    method StackNode (line 42) | public StackNode(String name) {
    method getName (line 46) | public String getName() {
    method getNameHtml (line 50) | public String getNameHtml(McpMapping mapping) {
    method getChildren (line 54) | public Collection<StackNode> getChildren() {
    method getChild (line 60) | public StackNode getChild(String name) {
    method getChild (line 69) | public StackNode getChild(String className, String methodName) {
    method getTotalTime (line 79) | public long getTotalTime() {
    method log (line 83) | public void log(long time) {
    method log (line 87) | private void log(StackTraceElement[] elements, int skip, long time) {
    method log (line 99) | public void log(StackTraceElement[] elements, long time) {
    method compareTo (line 103) | @Override
    method writeHtml (line 108) | private void writeHtml(StringBuilder builder, McpMapping mapping, long...
    method toHtml (line 137) | public String toHtml(McpMapping mapping) {
    method writeString (line 143) | private void writeString(StringBuilder builder, int indent) {
    method toString (line 159) | @Override
    method formatCssPct (line 166) | protected static String formatCssPct(double pct) {
    method escapeHtml (line 170) | protected static String escapeHtml(String str) {

FILE: src/main/java/com/sk89q/warmroast/StackTraceNode.java
  class StackTraceNode (line 23) | public class StackTraceNode extends StackNode {
    method StackTraceNode (line 28) | public StackTraceNode(String className, String methodName) {
    method getClassName (line 34) | public String getClassName() {
    method getMethodName (line 38) | public String getMethodName() {
    method getNameHtml (line 42) | @Override
    method compareTo (line 85) | @Override

FILE: src/main/java/com/sk89q/warmroast/WarmRoast.java
  class WarmRoast (line 59) | public class WarmRoast extends TimerTask {
    method WarmRoast (line 75) | public WarmRoast(VirtualMachine vm, int interval) {
    method getData (line 80) | public Map<String, StackNode> getData() {
    method getNode (line 84) | private StackNode getNode(String name) {
    method getMapping (line 93) | public McpMapping getMapping() {
    method getFilterThread (line 97) | public String getFilterThread() {
    method setFilterThread (line 101) | public void setFilterThread(String filterThread) {
    method getEndTime (line 105) | public long getEndTime() {
    method setEndTime (line 109) | public void setEndTime(long l) {
    method connect (line 113) | public void connect()
    method getThreadMXBean (line 138) | private ThreadMXBean getThreadMXBean()
    method run (line 149) | @Override
    method start (line 177) | public void start(InetSocketAddress address) throws Exception {
    method main (line 201) | public static void main(String[] args) throws AgentLoadException {

FILE: src/main/resources/www/warmroast.js
  function extractTime (line 12) | function extractTime($el) {
Condensed preview — 14 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (48K chars).
[
  {
    "path": ".github/workflows/build.yml",
    "chars": 522,
    "preview": "name: Build\n\non:\n  - push\n  - pull_request\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n\n    steps:\n    - "
  },
  {
    "path": ".gitignore",
    "chars": 303,
    "preview": "# Eclipse stuff\n/.classpath\n/.project\n/.settings\n\n# netbeans\n/nbproject\n\n# we use maven!\n/build.xml\n\n# maven\n/target\n\n# "
  },
  {
    "path": "README.md",
    "chars": 3580,
    "preview": "WarmRoast\n=========\n\n*Note: This project is not actively maintained but should work. (2024)*\n\nWarmRoast attaches to Mine"
  },
  {
    "path": "pom.xml",
    "chars": 3526,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
  },
  {
    "path": "src/main/java/com/sk89q/warmroast/ClassMapping.java",
    "chars": 1878,
    "preview": "/*\n * WarmRoast\n * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>\n *\n * This program is free software: you can re"
  },
  {
    "path": "src/main/java/com/sk89q/warmroast/DataViewServlet.java",
    "chars": 3137,
    "preview": "/*\n * WarmRoast\n * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>\n *\n * This program is free software: you can re"
  },
  {
    "path": "src/main/java/com/sk89q/warmroast/McpMapping.java",
    "chars": 3866,
    "preview": "/*\n * WarmRoast\n * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>\n *\n * This program is free software: you can re"
  },
  {
    "path": "src/main/java/com/sk89q/warmroast/RoastOptions.java",
    "chars": 1948,
    "preview": "/*\n * WarmRoast\n * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>\n *\n * This program is free software: you can re"
  },
  {
    "path": "src/main/java/com/sk89q/warmroast/StackNode.java",
    "chars": 5503,
    "preview": "/*\n * WarmRoast\n * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>\n *\n * This program is free software: you can re"
  },
  {
    "path": "src/main/java/com/sk89q/warmroast/StackTraceNode.java",
    "chars": 3463,
    "preview": "/*\n * WarmRoast\n * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>\n *\n * This program is free software: you can re"
  },
  {
    "path": "src/main/java/com/sk89q/warmroast/WarmRoast.java",
    "chars": 12188,
    "preview": "/*\n * WarmRoast\n * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>\n *\n * This program is free software: you can re"
  },
  {
    "path": "src/main/resources/www/index.html",
    "chars": 295,
    "preview": "<!DOCTYPE html><html><head><title>WarmRoast</title>\n<style>@import url(style.css);</style>\n</head><body>\n<h1>WarmRoast</"
  },
  {
    "path": "src/main/resources/www/style.css",
    "chars": 3374,
    "preview": "@import url(http://fonts.googleapis.com/css?family=Lato);\n\nbody {\n    font-family: 'Lato', Arial, sans-serif;\n    font-s"
  },
  {
    "path": "src/main/resources/www/warmroast.js",
    "chars": 1199,
    "preview": "$(\".name\").on(\"click\", function(event) {\n    var $parent = $(this).parent();\n    if ($parent.hasClass(\"collapsed\")) {\n  "
  }
]

About this extraction

This page contains the full source code of the sk89q/WarmRoast GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 14 files (43.7 KB), approximately 11.1k tokens, and a symbol index with 58 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!