Interactieve Polyline PDF maken met GroupDocs Annotation - Java Tutorial

Introductie

Heb je ooit geprobeerd om complexe paden, verbindingen of relaties in je PDF‑documenten programmatisch te markeren? Je bent niet de enige. Veel ontwikkelaars hebben moeite met het toevoegen van interactieve visuele elementen aan documenten, vooral bij niet‑lineaire annotaties zoals polylijnen.

In deze uitgebreide gids zul je interactieve polyline PDF annotaties maken die niet alleen professioneel ogen, maar ook de interactiviteit bieden die je gebruikers verwachten. We lopen alles door, van het opzetten van de omgeving tot geavanceerde aanpassingen, en we laten je zelfs zien hoe je de oplossing integreert in een spring boot pdf annotation service en generate svg path java code on‑the‑fly.

Snelle Antwoorden

  • Wat is het primaire doel van een polyline‑annotatie? Het verbindt meerdere punten om complexe, interactieve paden in een PDF te vormen.
  • Welke bibliotheek maakt dit het gemakkelijkst in Java? GroupDocs.Annotation for Java.
  • Kan ik het gebruiken met Spring Boot? Ja – zie de Spring Boot‑integratiesectie.
  • Hoe definieer ik de vorm van de lijn? Door een SVG‑pad‑string op te geven (bijv. met generate svg path java).
  • Heb ik een licentie nodig? Een proeflicentie werkt voor ontwikkeling; een productielicentie is vereist voor implementatie.

Waarom GroupDocs.Annotation voor Java kiezen?

Voordat we in de implementatie duiken, laten we het grote vraagstuk aanpakken – waarom GroupDocs.Annotation boven andere oplossingen?

Vergeleken met handmatige PDF‑manipulatiebibliotheken (zoals iText of PDFBox) biedt GroupDocs.Annotation:

  • Vooraf gebouwde annotatietypen die gewoon werken
  • Ingebouwde afhandeling van gebruikersinteractie
  • Cross‑formaat compatibiliteit (niet alleen PDF’s)
  • Veel minder boilerplate‑code

Vergeleken met client‑side JavaScript‑oplossingen, krijg je:

  • Server‑side verwerking voor betere beveiliging
  • Geen afhankelijkheid van browsermogelijkheden
  • Consistente weergave in alle omgevingen
  • Enterprise‑grade prestaties voor grote documenten

Kort samengevat? GroupDocs.Annotation biedt de perfecte balans tussen functionaliteit en eenvoud, vooral voor create interactive polyline pdf scenario’s die precieze coördinatenafhandeling vereisen.

Wat je zult leren

Aan het einde van deze tutorial kun je:

  • GroupDocs.Annotation opzetten in je Java‑project (op de juiste manier)
  • Interactieve polyline PDF annotaties maken met aangepaste eigenschappen
  • Veelvoorkomende implementatie‑problemen afhandelen (we behandelen de lastige)
  • Prestaties optimaliseren voor enterprise‑schaal documentverwerking
  • Integreren met populaire Java‑frameworks zoals Spring Boot PDF annotation

Vereisten en Omgevingsconfiguratie

Laten we je ontwikkelomgeving klaar maken. Je hebt nodig:

Essentiële vereisten:

  • Java Development Kit (JDK) 8 of hoger (JDK 11+ aanbevolen)
  • Maven 3.6+ of Gradle 6+
  • Een IDE zoals IntelliJ IDEA of Eclipse
  • Basiskennis van Java‑programmeren en Maven‑dependency‑beheer

Prettig om te hebben:

  • Bekendheid met PDF‑structuurconcepten
  • Ervaring met op annotaties gebaseerde Java‑applicaties
  • Begrip van SVG‑padnotatie (voor generate svg path java aanpassing)

Maven‑configuratie

Begin met het toevoegen van GroupDocs.Annotation aan je Maven‑project. Hier is de volledige configuratie die je nodig hebt in je pom.xml:

<repositories>
   <repository>
      <id>repository.groupdocs.com</id>
      <name>GroupDocs Repository</name>
      <url>https://releases.groupdocs.com/annotation/java/</url>
   </repository>
</repositories>

<dependencies>
   <dependency>
      <groupId>com.groupdocs</groupId>
      <artifactId>groupdocs-annotation</artifactId>
      <version>25.2</version>
   </dependency>
</dependencies>

Pro Tip: Controleer altijd de nieuwste versie op de GroupDocs‑website. Versie 25.2 bevat significante prestatieverbeteringen voor polyline‑rendering, maar nieuwere versies kunnen extra functies hebben die je wilt.

Licentie‑configuratie

Hier blijven veel ontwikkelaars in het begin steken. GroupDocs.Annotation vereist een licentie voor productiegebruik, maar je hebt opties:

Voor ontwikkeling/testen:

Voor productie:

  • Koop een abonnement via de GroupDocs aankooppagina
  • Licentiekosten variëren afhankelijk van het type implementatie (enkele applicatie vs. site‑breed)

Basisomgevinginitialisatie

Voordat je annotaties maakt, moet je de Annotator‑klasse initialiseren. Dit is je belangrijkste toegangspunt voor alle annotatie‑operaties:

import com.groupdocs.annotation.Annotator;

// Initialize Annotator with your document
Annotator annotator = new Annotator("YOUR_DOCUMENT_DIRECTORY/input.pdf");

Belangrijke opmerking: Gebruik altijd try‑with‑resources of verwijder expliciet de Annotator‑instantie om geheugenlekken te voorkomen. We laten je de juiste patronen hieronder zien.

Stapsgewijze Implementatie‑gids

Nu het leuke deel – laten we je eerste polyline‑annotatie maken. We lopen elke stap door met duidelijke uitleg.

Begrijpen van Polyline‑annotaties

Voordat we in de code duiken, laten we verduidelijken wat polyline‑annotaties eigenlijk doen. In tegenstelling tot eenvoudige lijnannotaties die twee punten verbinden, kunnen polylijnen meerdere punten verbinden om complexe paden te creëren. Zie ze als:

  • Technische diagrammen – tonen van signaalpaden of workflow‑verbindingen
  • Educatieve inhoud – illustreren van geometrische concepten of processtromen
  • Juridische documenten – relaties tussen contractclausules markeren
  • Kaarten en blauwdrukken – routes of structurele verbindingen markeren

Het belangrijkste voordeel is interactiviteit – gebruikers kunnen hoveren, klikken en zelfs deze annotaties aanpassen afhankelijk van je implementatie.

Stap 1: Annotatiereacties maken

De meeste professionele annotatiesystemen bevatten commentaarmogelijkheden. Zo stel je reacties in die je polyline begeleiden:

import com.groupdocs.annotation.models.Reply;
import java.util.Calendar;

// Create reply instances with comments
Reply reply1 = new Reply();
reply1.setComment("First comment");
reply1.setRepliedOn(Calendar.getInstance().getTime());

Reply reply2 = new Reply();
reply2.setComment("Second comment");
reply2.setRepliedOn(Calendar.getInstance().getTime());

Waarom dit belangrijk is: Reacties geven context aan je annotaties. In samenwerkingsomgevingen zijn ze essentieel om uit te leggen waarom bepaalde paden of verbindingen gemarkeerd zijn.

Stap 2: Reacties organiseren

Vervolgens organiseer je je reacties in een collectie die aan de annotatie kan worden gekoppeld:

import java.util.ArrayList;
import java.util.List;

// Add replies to a list
List<Reply> replies = new ArrayList<>();
replies.add(reply1);
replies.add(reply2);

Best practice: Zelfs als je nu geen reacties nodig hebt, maakt het opzetten van de structuur nu het later toevoegen van samenwerkingsfuncties makkelijker.

Stap 3: Polyline maken en configureren

Hier gebeurt de magie. De PolylineAnnotation‑klasse biedt uitgebreide aanpassingsopties:

import com.groupdocs.annotation.models.PenStyle;
import com.groupdocs.annotation.models.Rectangle;
import com.groupdocs.annotation.models.annotationmodels.PolylineAnnotation;

// Initialize polyline annotation
PolylineAnnotation polyline = new PolylineAnnotation();
polyline.setBox(new Rectangle(250, 35, 102, 12)); // Position and size
polyline.setMessage("This is a polyline annotation"); // Annotation message
polyline.setOpacity(0.7); // Opacity (0-1)
polyline.setPageNumber(0); // Page index (0-based)
polyline.setPenColor(65535); // Color in ARGB format
polyline.setPenStyle(PenStyle.DOT); // Pen style options
polyline.setPenWidth((byte) 3); // Pen width in pixels

// Associate replies and define the path
polyline.setReplies(replies);
polyline.setSvgPath("M250.8280751173709,48.209295774647885l0.6986854460093896,0l0.6986854460093896,-1.3973708920187793...");

Begrijpen van de eigenschappen:

  • Box Rectangle – definieert het begrenzingsgebied voor de annotatie
  • Opacity – 0.7 biedt goede zichtbaarheid terwijl de leesbaarheid van het document behouden blijft
  • PenColor – gebruikt ARGB‑formaat (65535 = blauw in dit geval)
  • PenStyleDOT creëert een gestippelde lijn – ideaal om tijdelijke of voorgestelde paden aan te geven
  • SVGPath – deze string definieert de daadwerkelijke lijncoördinaten (meer hierover hieronder)

Stap 4: De annotatie toevoegen

Zodra geconfigureerd, is het toevoegen van de annotatie aan je document eenvoudig:

// Add the annotation using Annotator
annotator.add(polyline);

Stap 5: Opslaan en opruimen

Tot slot sla je je geannoteerde document op en maak je de resources correct vrij:

String outputPath = "YOUR_OUTPUT_DIRECTORY/Annotated.pdf";
annotator.save(outputPath); // Save annotated document

// Dispose of annotator resources
annotator.dispose();

Tip voor geheugenbeheer: Verwijder altijd de Annotator‑instantie. Voor webapplicaties die veel documenten verwerken, voorkomt dit geheugenlekken die je applicatie kunnen laten crashen.

Werken met SVG‑paden

Het SVG‑pad is waarschijnlijk het meest complexe deel van polyline‑annotaties, dus laten we het opsplitsen met praktische voorbeelden.

Basispad‑commando’s

SVG‑paden gebruiken een commando‑gebaseerde syntaxis:

  • M: Move to (beginpunt)
  • L: Line to (lijn naar punt tekenen)
  • l: Relative line to (relatieve coördinaten)

Eenvoudig voorbeeld – een basis L‑vormig pad:

M10,10 L50,10 L50,50

Complex voorbeeld – de lange string in het code‑blok creëert een meer ingewikkelde vorm met meerdere verbonden segmenten.

Paden programmatisch genereren

Voor dynamische applicaties wil je misschien SVG‑paden genereren uit coördinaat‑arrays:

public String generatePolylinePath(Point[] points) {
    if (points.length == 0) return "";
    
    StringBuilder path = new StringBuilder();
    path.append("M").append(points[0].x).append(",").append(points[0].y);
    
    for (int i = 1; i < points.length; i++) {
        path.append("L").append(points[i].x).append(",").append(points[i].y);
    }
    
    return path.toString();
}

Deze aanpak is vooral nuttig wanneer je generate svg path java code moet genereren op basis van gebruikersinteracties of data‑analyse resultaten.

Praktische Toepassingen en Use‑cases

Laten we enkele praktische scenario’s verkennen waar polyline‑annotaties uitblinken:

Technische documentatie

Scenario: Je maakt software‑architectuurdiagrammen die datastromen tussen componenten moeten tonen.

// Create annotation for data flow path
PolylineAnnotation dataFlow = new PolylineAnnotation();
dataFlow.setMessage("Data flow from API to Database");
dataFlow.setPenColor(0xFF0000FF); // Blue for data flow
dataFlow.setPenStyle(PenStyle.SOLID);
dataFlow.setPenWidth((byte) 2);
// SVG path would show the actual route through your architecture

Educatief materiaal

Scenario: Wiskundeboeken met geometrische bewijzen die interactieve pad‑markering nodig hebben.

// Highlight geometric proof steps
PolylineAnnotation proofStep = new PolylineAnnotation();
proofStep.setMessage("Proof step 3: Angle bisector construction");
proofStep.setPenColor(0xFF00FF00); // Green for completed steps
proofStep.setOpacity(0.8); // Slightly transparent to not obscure text

Juridische documentreview

Scenario: Contractanalyse waarbij je relaties tussen clausules moet tonen.

// Connect related contract sections
PolylineAnnotation clauseConnection = new PolylineAnnotation();
clauseConnection.setMessage("This clause relates to section 4.2");
clauseConnection.setPenStyle(PenStyle.DASH); // Dashed for suggestions
clauseConnection.setPenColor(0xFFFF9900); // Orange for attention

Integratie met populaire Java‑frameworks

Spring Boot‑integratie

Voor spring boot pdf annotation projecten wil je een service maken voor annotatiebeheer:

@Service
public class DocumentAnnotationService {
    
    public String addPolylineAnnotation(String documentPath, 
                                       PolylineConfig config) {
        try (Annotator annotator = new Annotator(documentPath)) {
            PolylineAnnotation polyline = createPolylineFromConfig(config);
            annotator.add(polyline);
            
            String outputPath = generateOutputPath(documentPath);
            annotator.save(outputPath);
            return outputPath;
        }
    }
    
    private PolylineAnnotation createPolylineFromConfig(PolylineConfig config) {
        // Implementation details based on your config structure
        // This pattern keeps your annotation logic organized and testable
    }
}

REST‑API‑integratie

Maak endpoints voor dynamische annotatie‑creatie:

@RestController
@RequestMapping("/api/annotations")
public class AnnotationController {
    
    @Autowired
    private DocumentAnnotationService annotationService;
    
    @PostMapping("/polyline")
    public ResponseEntity<String> addPolylineAnnotation(
            @RequestBody PolylineRequest request) {
        
        try {
            String result = annotationService.addPolylineAnnotation(
                request.getDocumentPath(), 
                request.getConfig()
            );
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            return ResponseEntity.badRequest()
                .body("Error adding annotation: " + e.getMessage());
        }
    }
}

Dit patroon stelt frontend‑applicaties in staat om dynamisch polyline‑annotaties toe te voegen op basis van gebruikersinteracties.

Prestatie‑optimalisatie en best practices

Geheugenbeheer

Bij het verwerken van meerdere documenten of grote bestanden is goed resource‑beheer cruciaal:

// Use try-with-resources for automatic cleanup
public void processMultipleDocuments(List<String> documentPaths) {
    for (String path : documentPaths) {
        try (Annotator annotator = new Annotator(path)) {
            // Process document
            addPolylineAnnotations(annotator);
            annotator.save(generateOutputPath(path));
        } // Automatic disposal happens here
    }
}

Batch‑verwerking

Voor grootschalige operaties, overweeg batch‑verwerking:

public void batchAddPolylines(String documentPath, 
                             List<PolylineConfig> configs) {
    try (Annotator annotator = new Annotator(documentPath)) {
        // Add all annotations before saving
        for (PolylineConfig config : configs) {
            PolylineAnnotation polyline = createFromConfig(config);
            annotator.add(polyline);
        }
        // Single save operation is more efficient
        annotator.save(generateOutputPath(documentPath));
    }
}

SVG‑pad‑optimalisatie

Complexe SVG‑paden kunnen de weergave vertragen. Hier zijn optimalisatiestrategieën:

  1. Paden vereenvoudigen – verwijder onnodige coördinatenprecisie
  2. Gebruik relatieve commando’s – kleinere bestandsgroottes met l in plaats van L
  3. Batch vergelijkbare annotaties – groepeer annotaties met vergelijkbare eigenschappen
// Optimize coordinate precision
public String optimizePath(String svgPath) {
    return svgPath.replaceAll("(\\d+\\.\\d{3})\\d+", "$1");
}

Veelvoorkomende problemen en oplossingen

Probleem 1: “Annotatie niet zichtbaar”

Symptomen: Code draait zonder fouten, maar de polyline verschijnt niet.

Onjuiste oorzaken:

  • Onjuist paginanummer (onthoud, het is 0‑gebaseerd)
  • SVG‑padcoördinaten buiten de documentgrenzen
  • Opacity te laag ingesteld of pen‑breedte te klein

Oplossing:

// Debug your annotation placement
PolylineAnnotation polyline = new PolylineAnnotation();
polyline.setPageNumber(0); // Ensure correct page
polyline.setOpacity(1.0); // Full opacity for testing
polyline.setPenWidth((byte) 5); // Thicker line for visibility

// Log the bounding box to verify coordinates
Rectangle box = polyline.getBox();
System.out.println("Annotation bounds: " + box.getX() + "," + box.getY());

Probleem 2: “OutOfMemoryError met grote documenten”

Symptomen: Applicatie crasht bij het verwerken van grote PDF’s of meerdere documenten.

Oplossing:

// Implement proper memory management
public void processLargeDocument(String documentPath) {
    // Process in smaller batches
    int maxAnnotationsPerBatch = 50;
    List<PolylineConfig> allConfigs = getAnnotationConfigs();
    
    for (int i = 0; i < allConfigs.size(); i += maxAnnotationsPerBatch) {
        try (Annotator annotator = new Annotator(documentPath)) {
            int end = Math.min(i + maxAnnotationsPerBatch, allConfigs.size());
            List<PolylineConfig> batch = allConfigs.subList(i, end);
            
            processBatch(annotator, batch);
            annotator.save(generateBatchOutputPath(documentPath, i));
        }
        // Force garbage collection between batches if needed
        System.gc();
    }
}

Probleem 3: “Ongeldig SVG‑padformaat”

Symptomen: Exceptie gegooid bij het instellen van het SVG‑pad.

Onjuiste oorzaken:

  • Misvormde SVG‑syntaxis
  • Ontbrekend move‑commando aan het begin
  • Ongeldige coördinaatwaarden

Oplossing:

// Validate SVG path before using
public boolean isValidSVGPath(String path) {
    // Basic validation - should start with M or m
    if (!path.matches("^[Mm]\\d+.*")) {
        return false;
    }
    
    // Additional validation logic here
    return true;
}

// Use validated paths only
if (isValidSVGPath(pathString)) {
    polyline.setSvgPath(pathString);
} else {
    throw new IllegalArgumentException("Invalid SVG path: " + pathString);
}

Probleem 4: “Licentie‑verificatie mislukt”

Symptomen: Applicatie gooit licentie‑gerelateerde excepties in productie.

Oplossing:

// Proper license initialization
public class AnnotationConfig {
    
    @PostConstruct
    public void initializeLicense() {
        try {
            // Load license from classpath or file system
            String licensePath = getClass().getClassLoader()
                .getResource("GroupDocs.Annotation.lic").getPath();
            
            License license = new License();
            license.setLicense(licensePath);
            
            System.out.println("GroupDocs.Annotation license loaded successfully");
        } catch (Exception e) {
            System.err.println("Failed to load license: " + e.getMessage());
            // Handle license failure appropriately
        }
    }
}

Geavanceerde aanpassingstechnieken

Dynamische kleurtoewijzing

Maak polylijnen met kleuren gebaseerd op data of gebruikersvoorkeuren:

public class ColorHelper {
    private static final Map<String, Integer> CATEGORY_COLORS = Map.of(
        "error", 0xFFFF0000,      // Red
        "warning", 0xFFFF9900,    // Orange  
        "info", 0xFF0099FF,       // Blue
        "success", 0xFF00FF00     // Green
    );
    
    public static int getColorForCategory(String category) {
        return CATEGORY_COLORS.getOrDefault(category, 0xFF000000); // Default black
    }
}

Interactieve annotaties met aangepaste eigenschappen

Voeg aangepaste metadata toe aan je annotaties voor verbeterde interactiviteit:

// Create custom annotation with metadata
PolylineAnnotation polyline = new PolylineAnnotation();
polyline.setMessage("Process Flow: " + processName);

// Add custom properties (stored in message or replies)
Reply metadataReply = new Reply();
metadataReply.setComment("metadata:{\"processId\":\"12345\",\"priority\":\"high\"}");
polyline.setReplies(Arrays.asList(metadataReply));

Deze aanpak stelt frontend‑applicaties in staat om de metadata te extraheren en te gebruiken voor rijkere gebruikerservaringen.

Testen van je implementatie

Unit‑testen

Maak uitgebreide tests voor je annotatielogica:

@Test
public void testPolylineAnnotationCreation() {
    // Arrange
    String documentPath = "test-documents/sample.pdf";
    PolylineConfig config = new PolylineConfig();
    config.setMessage("Test polyline");
    config.setPath("M10,10L50,50");
    
    // Act
    try (Annotator annotator = new Annotator(documentPath)) {
        PolylineAnnotation polyline = createPolylineFromConfig(config);
        annotator.add(polyline);
        
        // Assert
        assertNotNull(polyline);
        assertEquals("Test polyline", polyline.getMessage());
        assertEquals(0.7, polyline.getOpacity(), 0.01);
    }
}

Integratietesten

Test de volledige workflow met echte documenten:

@Test
public void testEndToEndAnnotationWorkflow() {
    // Test complete process from document input to annotated output
    String inputPath = "test-documents/input.pdf";
    String outputPath = "test-output/annotated.pdf";
    
    DocumentAnnotationService service = new DocumentAnnotationService();
    String result = service.addPolylineAnnotation(inputPath, createTestConfig());
    
    // Verify output file exists and contains annotations
    assertTrue(Files.exists(Paths.get(result)));
    
    // Additional verification logic
    verifyAnnotationExists(result);
}

Conclusie

Je hebt zojuist geleerd hoe je interactieve polyline PDF annotaties maakt met GroupDocs.Annotation voor Java. Polyline‑annotaties bieden mogelijkheden om interactieve, professionele documenten te maken die veel verder gaan dan statische tekst.

Key takeaways:

  • Setup is straightforward zodra je Maven‑configuratie en licentiëring begrijpt
  • SVG‑paden bieden ongelooflijke flexibiliteit voor het maken van complexe verbonden lijnen
  • Goed resource‑beheer is cruciaal voor productie‑applicaties
  • Integratie‑patronen (Spring Boot, REST) maken het eenvoudig om annotaties toe te voegen aan bestaande Java‑applicaties

Of je nu documentbeheersystemen, educatieve platforms of technische documentatietools bouwt, polyline‑annotaties bieden de visuele duidelijkheid en interactiviteit die je gebruikers nodig hebben.

Volgende stappen

Klaar om je annotatie‑vaardigheden verder te ontwikkelen? Overweeg het volgende:

  • Area‑annotaties voor het markeren van complexe gebieden
  • Pijl‑annotaties voor richting‑indicatoren
  • Watermerk‑annotaties voor branding en beveiliging
  • Integratie met document‑viewers voor realtime annotatie‑bewerking

Veelgestelde vragen

V: Kan ik polyline‑annotaties aanpassen nadat ze zijn aangemaakt?
A: Ja, maar je moet de bestaande annotatie verwijderen en een nieuwe toevoegen met bijgewerkte eigenschappen. GroupDocs.Annotation ondersteunt geen directe wijziging van bestaande annotaties.

V: Wat is het maximale aantal punten dat ik in een polyline kan opnemen?
A: Er is geen harde limiet, maar de prestaties nemen af bij extreem complexe paden (1000+ punten). Voor de beste resultaten houd je polylijnen onder 100 coördinaatpunten.

V: Kunnen gebruikers interageren met polyline‑annotaties in PDF‑viewers?
A: Ja, wanneer bekeken in compatibele PDF‑readers kunnen gebruikers op annotaties klikken om commentaren en reacties te zien. Het niveau van interactiviteit hangt af van de gebruikte PDF‑viewer.

V: Hoe ga ik om met verschillende coördinatensystemen tussen documenttypes?
A: GroupDocs.Annotation normaliseert coördinatensystemen intern, maar je moet testen met je specifieke documenttypes. PDF‑coördinaten beginnen links‑onder, terwijl sommige formaten een links‑boven oorsprong gebruiken.

V: Kan ik annotatiedata exporteren zonder het originele document?
A: Ja, GroupDocs.Annotation biedt methoden om annotatiemetadata te extraheren als XML of JSON, die apart opgeslagen en later opnieuw toegepast kunnen worden.

V: Wat is de prestatie‑impact van het toevoegen van veel polyline‑annotaties?
A: Elke annotatie voegt minimale overhead toe, maar complexe SVG‑paden en talrijke annotaties kunnen de weergave vertragen. Gebruik batch‑verwerking en optimaliseer SVG‑paden voor de beste prestaties.

V: Hoe ga ik om met versie‑compatibiliteit bij het upgraden van GroupDocs.Annotation?
A: Test altijd eerst met een kleine subset van je documenten. GroupDocs behoudt backward compatibility voor annotatiedata, maar API‑methoden kunnen veranderen tussen grote versies.

Resources en verdere lectuur


Laatst bijgewerkt: 2026-03-03
Getest met: GroupDocs.Annotation 25.2 for Java
Auteur: GroupDocs