Commit 025527ef0731

Vincent Demeester <vincent@sbr.pm>
2026-03-27 11:53:55
feat(daily-plan): Emacs UX + remove review-tool
Enhanced daily-plan.el with full weekly review rendering (org done, AI sessions, reviews, discussions, comments), section folding via TAB, period switching with 'p', yank as markdown with 'y', and C-c d r for review command. Removed review-tool — all functionality now in daily-plan.
1 parent 66247b7
dots/config/emacs/init.el
@@ -2255,7 +2255,8 @@ parameter), remove all other windows so the capture buffer fills the frame."
 ;; Daily Plan - Jira/GitHub → org-mode scheduling
 (use-package daily-plan
   :commands (daily-plan-show daily-plan-inbox daily-plan-weekly
-             daily-plan-schedule daily-plan-schedule-at-point)
+             daily-plan-review daily-plan-schedule
+             daily-plan-schedule-at-point daily-plan-yank-markdown)
   :bind-keymap ("C-c d" . daily-plan-prefix-map)
   :config
   (defvar daily-plan-prefix-map
@@ -2263,6 +2264,7 @@ parameter), remove all other windows so the capture buffer fills the frame."
       (define-key map "d" #'daily-plan-show)
       (define-key map "i" #'daily-plan-inbox)
       (define-key map "w" #'daily-plan-weekly)
+      (define-key map "r" #'daily-plan-review)
       (define-key map "s" #'daily-plan-schedule)
       map)
     "Keymap for daily-plan commands under C-c d."))
pkgs/default.nix
@@ -34,7 +34,6 @@ in
   nix-flake-update = pkgs.callPackage ../tools/nix-flake-update { };
   slack-archive = pkgs.callPackage ../tools/slack-archive { };
   gcal-to-org = pkgs.callPackage ../tools/gcal-to-org { };
-  review-tool = pkgs.callPackage ../tools/review-tool { };
   daily-plan = pkgs.callPackage ../tools/daily-plan { };
   github-notif-manager = pkgs.callPackage ../tools/github-notif-manager { };
   beets-lidarr-fields = pkgs.python3Packages.callPackage ./beets-lidarr-fields { };
tools/daily-plan/daily-plan.el
@@ -9,11 +9,15 @@
 ;;   RET - open item URL in browser
 ;;   g   - refresh buffer
 ;;   q   - quit
+;;   y   - yank buffer as markdown (for reports)
+;;   p   - switch period (weekly/review buffers)
+;;   TAB - cycle section visibility
 ;;
 ;; Interactive commands:
 ;;   M-x daily-plan-show      - today's plan
 ;;   M-x daily-plan-inbox     - new items since last check
 ;;   M-x daily-plan-weekly    - weekly review
+;;   M-x daily-plan-review    - full activity review (markdown output)
 ;;   M-x daily-plan-schedule  - schedule by key
 
 ;;; Code:
@@ -27,6 +31,18 @@
 (defvar daily-plan-org-file (expand-file-name "~/desktop/org/todos.org")
   "Path to the org file for scheduling.")
 
+(defvar-local daily-plan--current-period nil
+  "Current period for review/weekly buffers.")
+
+(defvar-local daily-plan--current-command nil
+  "Current command for refresh.")
+
+(defvar-local daily-plan--current-args nil
+  "Current args for refresh.")
+
+(defvar-local daily-plan--current-render-fn nil
+  "Current render function for refresh.")
+
 ;; ── JSON helpers ──
 
 (defun daily-plan--run-json (&rest args)
@@ -54,6 +70,10 @@
     (define-key map (kbd "RET") #'daily-plan-open-at-point)
     (define-key map (kbd "g") #'daily-plan-refresh)
     (define-key map (kbd "q") #'quit-window)
+    (define-key map (kbd "y") #'daily-plan-yank-markdown)
+    (define-key map (kbd "p") #'daily-plan-switch-period)
+    (define-key map (kbd "TAB") #'org-cycle)
+    (define-key map (kbd "S-TAB") #'org-shifttab)
     map)
   "Keymap for `daily-plan-mode'.")
 
@@ -63,7 +83,7 @@
   (read-only-mode 1)
   (setq-local buffer-read-only t))
 
-;; ── Rendering ──
+;; ── Rendering helpers ──
 
 (defun daily-plan--insert-jira-item (item)
   "Insert a single Jira ITEM as an org list entry with text properties."
@@ -97,6 +117,41 @@
         (funcall insert-fn item))
     (insert (format "- %s\n" (or empty-msg "(none)")))))
 
+(defun daily-plan--insert-org-done-item (item)
+  "Insert a completed org ITEM."
+  (let-alist item
+    (insert (format "- ✓ %s /(%s)/\n" .title .completed_at))))
+
+(defun daily-plan--insert-discussion-item (item)
+  "Insert a GitHub discussion ITEM."
+  (let-alist item
+    (let ((start (point)))
+      (insert (format "- [[%s][%s]] %s" .url .repo .title))
+      (when (and .category (not (string-empty-p .category)))
+        (insert (format " =[%s]=" .category)))
+      (insert "\n")
+      (put-text-property start (point) 'daily-plan-url .url)
+      (put-text-property start (point) 'daily-plan-type "discussion"))))
+
+(defun daily-plan--insert-comment-item (item)
+  "Insert a GitHub comment ITEM."
+  (let-alist item
+    (let ((start (point))
+          (ref (format "%s#%d" .repo .issue_number)))
+      (insert (format "- [[%s][%s]] %s\n" .url ref .issue_title))
+      (put-text-property start (point) 'daily-plan-url .url)
+      (put-text-property start (point) 'daily-plan-type "comment"))))
+
+(defun daily-plan--insert-ai-item (item)
+  "Insert an AI session ITEM."
+  (let-alist item
+    (insert (format "- *%s* %s" .type .title))
+    (when (and .project (not (string-empty-p .project)))
+      (insert (format " =[%s]=" .project)))
+    (insert (format " /(%s)/\n" .date))))
+
+;; ── Render: show ──
+
 (defun daily-plan--render-show (data)
   "Render show DATA into current buffer."
   (let-alist data
@@ -124,14 +179,15 @@
     (insert "\n** GitHub — Your Open PRs\n")
     (daily-plan--insert-items .github_prs #'daily-plan--insert-gh-item nil)))
 
+;; ── Render: inbox ──
+
 (defun daily-plan--insert-advisory (item)
   "Insert a GitHub security advisory ITEM."
   (let-alist item
     (let ((start (point))
           (id (or .cve_id .ghsa_id)))
-      (insert (format "- [[%s][%s]] %s =%s= /%s/"
+      (insert (format "- [[%s][%s]] %s =%s= /%s/\n"
                       .url id .summary .severity .repo))
-      (insert "\n")
       (put-text-property start (point) 'daily-plan-key id)
       (put-text-property start (point) 'daily-plan-url .url)
       (put-text-property start (point) 'daily-plan-type "advisory"))))
@@ -141,9 +197,8 @@
   (let-alist item
     (let ((start (point))
           (id (or .cve "dependabot")))
-      (insert (format "- [[%s][%s]] %s =%s= ~%s~ /%s/"
+      (insert (format "- [[%s][%s]] %s =%s= ~%s~ /%s/\n"
                       .url id .summary .severity .package .repo))
-      (insert "\n")
       (put-text-property start (point) 'daily-plan-key id)
       (put-text-property start (point) 'daily-plan-url .url)
       (put-text-property start (point) 'daily-plan-type "dependabot"))))
@@ -153,10 +208,10 @@
   (let-alist data
     (insert (format "* Inbox — Since %s\n\n" .since))
 
-    (insert "** GitHub — Security Advisories (triage/draft)  :security:\n")
+    (insert "** Security Advisories (triage/draft)  :security:\n")
     (daily-plan--insert-items .github_security_advisories #'daily-plan--insert-advisory nil)
 
-    (insert "\n** GitHub — Dependabot Alerts (critical/high)  :security:\n")
+    (insert "\n** Dependabot Alerts (critical/high)  :security:\n")
     (daily-plan--insert-items .github_dependabot_alerts #'daily-plan--insert-dependabot nil)
 
     (insert "\n** Jira — CVEs / Security Issues  :security:\n")
@@ -176,27 +231,82 @@
     (insert "\n** GitHub — Review Requests  :review:\n")
     (daily-plan--insert-items .github_reviews #'daily-plan--insert-gh-item nil)))
 
+;; ── Render: weekly ──
+
 (defun daily-plan--render-weekly (data)
   "Render weekly DATA into current buffer."
   (let-alist data
     (insert (format "* Weekly Review — %s\n\n" .week))
 
+    ;; Org completed tasks
+    (when .org_done
+      (insert "** Completed Tasks (Org)  :done:\n")
+      ;; Group by section
+      (let ((by-section (make-hash-table :test 'equal))
+            (order '()))
+        (dolist (item .org_done)
+          (let ((section (or (alist-get 'section item) "(uncategorized)")))
+            (unless (gethash section by-section)
+              (push section order))
+            (push item (gethash section by-section))))
+        (dolist (section (nreverse order))
+          (insert (format "*** %s\n" section))
+          (dolist (item (nreverse (gethash section by-section)))
+            (daily-plan--insert-org-done-item item))))
+      (insert "\n"))
+
+    ;; AI sessions
+    (when .ai_sessions
+      (let ((filtered (seq-remove
+                       (lambda (item)
+                         (string-match-p "auto-recovered"
+                                         (downcase (or (alist-get 'title item) ""))))
+                       .ai_sessions)))
+        (when filtered
+          (insert (format "** AI Sessions (%d)  :ai:\n" (length filtered)))
+          (dolist (item filtered)
+            (daily-plan--insert-ai-item item))
+          (insert "\n"))))
+
+    ;; Jira completed
     (insert "** Completed (Jira)  :done:\n")
     (daily-plan--insert-items .jira_completed #'daily-plan--insert-jira-item "(nothing completed)")
 
-    (insert "\n** Completed (GitHub — Merged PRs)  :done:\n")
+    ;; GitHub merged
+    (insert "\n** Merged PRs  :done:\n")
     (daily-plan--insert-items .github_merged #'daily-plan--insert-gh-item "(no merged PRs)")
 
+    ;; Reviews given
+    (when .github_reviewed
+      (insert (format "\n** Reviews Given (%d)  :review:\n" (length .github_reviewed)))
+      (daily-plan--insert-items .github_reviewed #'daily-plan--insert-gh-item nil))
+
+    ;; Issues filed
+    (when .github_issues_created
+      (insert (format "\n** Issues Filed (%d)\n" (length .github_issues_created)))
+      (daily-plan--insert-items .github_issues_created #'daily-plan--insert-gh-item nil))
+
+    ;; Discussions
+    (when .github_discussions
+      (insert (format "\n** Discussions (%d)  :community:\n" (length .github_discussions)))
+      (daily-plan--insert-items .github_discussions #'daily-plan--insert-discussion-item nil))
+
+    ;; Comments
+    (when .github_comments
+      (insert (format "\n** Comments (%d)\n" (length .github_comments)))
+      (daily-plan--insert-items .github_comments #'daily-plan--insert-comment-item nil))
+
+    ;; Still in progress
     (insert "\n** Still In Progress\n")
     (daily-plan--insert-items .jira_in_progress #'daily-plan--insert-jira-item nil)
 
+    ;; Backlog
     (insert "\n** Backlog — Candidates for Next Week\n")
     (daily-plan--insert-items .jira_backlog #'daily-plan--insert-jira-item nil)
 
+    ;; Assigned issues
     (insert "\n** GitHub Issues (assigned)\n")
-    (daily-plan--insert-items .github_issues #'daily-plan--insert-gh-item nil)
-
-    (insert (format "\n/Schedule: daily-plan schedule SRVKP-1234 %s/\n" .next_monday))))
+    (daily-plan--insert-items .github_issues #'daily-plan--insert-gh-item nil)))
 
 ;; ── Buffer management ──
 
@@ -209,6 +319,9 @@
         (erase-buffer)
         (funcall render-fn data)
         (daily-plan-mode)
+        ;; Fold all sections to level 2 for overview
+        (goto-char (point-min))
+        (org-content 2)
         (goto-char (min pos (point-max)))))
     (pop-to-buffer buf)))
 
@@ -222,7 +335,9 @@
       (let ((inhibit-read-only t))
         (erase-buffer)
         (insert "Loading...")
-        (daily-plan-mode)))
+        (daily-plan-mode)
+        (setq-local daily-plan--current-args args)
+        (setq-local daily-plan--current-render-fn render-fn)))
     (pop-to-buffer buf)
     ;; Run async
     (make-process
@@ -241,6 +356,10 @@
                (if data
                    (progn
                      (daily-plan--create-buffer buf-name render-fn data)
+                     ;; Preserve local vars after re-render
+                     (with-current-buffer buf-name
+                       (setq-local daily-plan--current-args args)
+                       (setq-local daily-plan--current-render-fn render-fn))
                      (message "%s ready." buf-name))
                  (message "Failed to parse %s output" buf-name)))
            (message "daily-plan failed with exit code %d" (process-exit-status proc)))
@@ -269,6 +388,19 @@
   (interactive)
   (daily-plan--run-async "*daily-plan-weekly*" '("weekly") #'daily-plan--render-weekly))
 
+;;;###autoload
+(defun daily-plan-review (&optional period)
+  "Show full activity review for PERIOD.
+PERIOD can be \"this week\", \"last week\", \"this month\", etc."
+  (interactive
+   (list (completing-read "Period: "
+                          '("this week" "last week" "this month" "last month")
+                          nil nil nil nil "this week")))
+  (let* ((buf-name (format "*daily-plan-review [%s]*" period))
+         (args (list "review" period)))
+    (setq daily-plan--current-period period)
+    (daily-plan--run-async buf-name args #'daily-plan--render-weekly)))
+
 ;;;###autoload
 (defun daily-plan-schedule (key &optional date)
   "Schedule a Jira or GitHub issue KEY for DATE.
@@ -310,12 +442,41 @@ KEY should be PROJ-123 for Jira or owner/repo#123 for GitHub."
 (defun daily-plan-refresh ()
   "Refresh the current daily-plan buffer."
   (interactive)
-  (let ((buf-name (buffer-name)))
+  (let ((args daily-plan--current-args)
+        (render-fn daily-plan--current-render-fn)
+        (buf-name (buffer-name)))
     (cond
+     ;; Use stored args/render if available
+     ((and args render-fn)
+      (daily-plan--run-async buf-name args render-fn))
+     ;; Fallback by buffer name
      ((string= buf-name "*daily-plan*") (daily-plan-show))
      ((string= buf-name "*daily-plan-inbox*") (daily-plan-inbox))
      ((string= buf-name "*daily-plan-weekly*") (daily-plan-weekly))
      (t (message "Not a daily-plan buffer")))))
 
+(defun daily-plan-switch-period ()
+  "Switch the time period for review/weekly buffers."
+  (interactive)
+  (let ((period (completing-read "Period: "
+                                 '("this week" "last week" "this month" "last month")
+                                 nil nil nil nil (or daily-plan--current-period "this week"))))
+    (cond
+     ((string-match-p "review" (buffer-name))
+      (daily-plan-review period))
+     ((string-match-p "weekly" (buffer-name))
+      ;; Weekly always uses "this week", suggest review instead
+      (daily-plan-review period))
+     (t (daily-plan-review period)))))
+
+(defun daily-plan-yank-markdown ()
+  "Copy the current buffer content as markdown to the kill ring.
+Runs `daily-plan review` with the current period to get markdown."
+  (interactive)
+  (let* ((period (or daily-plan--current-period "this week"))
+         (output (daily-plan--run-plain "review" period)))
+    (kill-new output)
+    (message "Markdown copied to kill ring (%d chars)" (length output))))
+
 (provide 'daily-plan)
 ;;; daily-plan.el ends here
tools/review-tool/cmd/review-tool/main.go
@@ -1,227 +0,0 @@
-// Package main provides the review-tool CLI.
-package main
-
-import (
-	"context"
-	"fmt"
-	"os"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-	"github.com/vdemeester/home/tools/review-tool/internal/filter"
-	"github.com/vdemeester/home/tools/review-tool/internal/output"
-	"github.com/vdemeester/home/tools/review-tool/internal/sources"
-	"github.com/vdemeester/home/tools/review-tool/internal/timerange"
-)
-
-var (
-	cfgFile        string
-	outputFormat   string
-	sourcesFlag    []string
-	includeFolders []string
-	excludeFolders []string
-)
-
-func main() {
-	if err := run(os.Args[1:]); err != nil {
-		fmt.Fprintf(os.Stderr, "error: %v\n", err)
-		os.Exit(1)
-	}
-}
-
-func run(args []string) error {
-	// Parse flags
-	var timeRangeStr string
-	var showHelp bool
-
-	for i := 0; i < len(args); i++ {
-		arg := args[i]
-		switch {
-		case arg == "-h" || arg == "--help":
-			showHelp = true
-		case arg == "-c" || arg == "--config":
-			if i+1 < len(args) {
-				i++
-				cfgFile = args[i]
-			}
-		case arg == "-f" || arg == "--format":
-			if i+1 < len(args) {
-				i++
-				outputFormat = args[i]
-			}
-		case arg == "-s" || arg == "--source":
-			if i+1 < len(args) {
-				i++
-				sourcesFlag = append(sourcesFlag, args[i])
-			}
-		case arg == "-d" || arg == "--folder":
-			if i+1 < len(args) {
-				i++
-				includeFolders = append(includeFolders, args[i])
-			}
-		case arg == "-D" || arg == "--exclude-folder":
-			if i+1 < len(args) {
-				i++
-				excludeFolders = append(excludeFolders, args[i])
-			}
-		case arg == "config":
-			return runConfigCmd()
-		case arg == "sources":
-			return runSourcesCmd()
-		case arg[0] != '-':
-			timeRangeStr = arg
-		}
-	}
-
-	if showHelp {
-		printHelp()
-		return nil
-	}
-
-	return runReview(timeRangeStr)
-}
-
-func printHelp() {
-	fmt.Println(`review-tool - Generate activity review reports from multiple sources
-
-Usage:
-  review-tool [time-range] [flags]
-  review-tool [command]
-
-Commands:
-  config    Show current configuration
-  sources   List available data sources
-
-Arguments:
-  time-range  Natural language time range (default: "last week")
-              Examples: today, yesterday, "this week", "last week",
-                        "past 3 days", "this month", "2026-01-01..2026-01-15"
-
-Flags:
-  -c, --config string          Config file (default: ~/.config/review-tool/config.yaml)
-  -f, --format string          Output format: markdown, json, yaml/llm (default from config)
-  -s, --source string          Sources to include (can be repeated)
-  -d, --folder string          Include only items matching folder (can be repeated)
-  -D, --exclude-folder string  Exclude items matching folder (can be repeated)
-  -h, --help                   Show this help message
-
-Folder filtering:
-  Matches against project, repository, and directory metadata (substring,
-  case-insensitive). Parenthetical descriptions are stripped before matching.
-
-Examples:
-  review-tool                                          # Last week's activity
-  review-tool today                                    # Today's activity
-  review-tool "past 3 days"                            # Last 3 days
-  review-tool -f json "this week"                      # JSON output
-  review-tool -s github -s org                         # Only GitHub and org
-  review-tool -d tektoncd                              # Only tektoncd projects
-  review-tool -d tektoncd -d chisel                    # tektoncd OR chisel
-  review-tool -D home                                  # Exclude homelab
-  review-tool -d tektoncd -D tektoncd/plumbing         # tektoncd except plumbing`)
-}
-
-func runReview(timeRangeStr string) error {
-	// Load config
-	cfg, err := config.Load(cfgFile)
-	if err != nil {
-		return fmt.Errorf("failed to load config: %w", err)
-	}
-
-	// Parse time range
-	if timeRangeStr == "" {
-		timeRangeStr = "last week"
-	}
-
-	tr, err := timerange.Parse(timeRangeStr)
-	if err != nil {
-		return fmt.Errorf("invalid time range: %w", err)
-	}
-
-	// Create source registry
-	registry := sources.NewRegistry(cfg)
-
-	// Fetch from sources
-	ctx := context.Background()
-	var activities map[string]*activity.Activity
-	if len(sourcesFlag) > 0 {
-		activities = registry.FetchSelected(ctx, tr.Start, tr.End, sourcesFlag)
-	} else {
-		activities = registry.FetchAll(ctx, tr.Start, tr.End)
-	}
-
-	// Apply folder filters
-	f := &filter.Filter{
-		IncludeFolders: includeFolders,
-		ExcludeFolders: excludeFolders,
-	}
-	f.Apply(activities)
-
-	// Build report
-	report := &activity.ReviewReport{
-		GeneratedAt: time.Now(),
-		TimeRange:   *tr,
-		Activities:  activities,
-	}
-
-	if cfg.Output.IncludeSummary {
-		report.CalculateSummary()
-	}
-
-	// Output
-	format := outputFormat
-	if format == "" {
-		format = cfg.Output.DefaultFormat
-	}
-
-	switch format {
-	case "json":
-		return output.WriteJSON(os.Stdout, report)
-	case "yaml", "llm":
-		return output.WriteYAML(os.Stdout, report)
-	default:
-		return output.WriteMarkdown(os.Stdout, report)
-	}
-}
-
-func runConfigCmd() error {
-	cfg, err := config.Load(cfgFile)
-	if err != nil {
-		return err
-	}
-
-	fmt.Printf("Config file: %s\n\n", config.DefaultConfigPath())
-	fmt.Printf("User: %s <%s>\n\n", cfg.User.Name, cfg.User.Email)
-
-	fmt.Println("Sources:")
-	fmt.Printf("  GitHub:  enabled=%v\n", cfg.GitHub.Enabled)
-	fmt.Printf("  Org:     enabled=%v, files=%d\n", cfg.Org.Enabled, len(cfg.Org.Files))
-	fmt.Printf("  Jira:    enabled=%v\n", cfg.Jira.Enabled)
-	fmt.Printf("  AI:      enabled=%v, dir=%s\n", cfg.AI.Enabled, cfg.AI.Dir)
-
-	fmt.Printf("\nOutput: format=%s, summary=%v\n", cfg.Output.DefaultFormat, cfg.Output.IncludeSummary)
-
-	return nil
-}
-
-func runSourcesCmd() error {
-	cfg, err := config.Load(cfgFile)
-	if err != nil {
-		return err
-	}
-
-	registry := sources.NewRegistry(cfg)
-
-	fmt.Println("Available sources:")
-	for _, name := range registry.Sources() {
-		source, _ := registry.Get(name)
-		status := "ok"
-		if err := source.Validate(); err != nil {
-			status = fmt.Sprintf("error: %v", err)
-		}
-		fmt.Printf("  %s: %s\n", name, status)
-	}
-
-	return nil
-}
tools/review-tool/internal/activity/activity.go
@@ -1,73 +0,0 @@
-// Package activity defines the core types for activity tracking.
-package activity
-
-import "time"
-
-// Category represents the source category of an activity.
-type Category string
-
-const (
-	CategoryGitHub Category = "github"
-	CategoryOrg    Category = "org"
-	CategoryJira   Category = "jira"
-	CategoryAI     Category = "ai"
-)
-
-// ActivityItem represents a single unit of work or event.
-type ActivityItem struct {
-	ID          string            `json:"id"`
-	Title       string            `json:"title"`
-	Description string            `json:"description,omitempty"`
-	Category    Category          `json:"category"`
-	Type        string            `json:"type"` // e.g., "pr_merged", "todo_done", "issue_updated", "session"
-	Timestamp   time.Time         `json:"timestamp"`
-	URL         string            `json:"url,omitempty"`
-	Metadata    map[string]string `json:"metadata,omitempty"`
-}
-
-// Activity aggregates items from a single source.
-type Activity struct {
-	Source string         `json:"source"`
-	Items  []ActivityItem `json:"items"`
-	Error  string         `json:"error,omitempty"`
-}
-
-// TimeRange represents the query period.
-type TimeRange struct {
-	Start       time.Time `json:"start"`
-	End         time.Time `json:"end"`
-	Description string    `json:"description"` // e.g., "last week"
-}
-
-// Summary provides high-level metrics.
-type Summary struct {
-	TotalItems      int            `json:"total_items"`
-	ItemsByCategory map[string]int `json:"items_by_category"`
-	ItemsByType     map[string]int `json:"items_by_type"`
-}
-
-// ReviewReport is the complete output.
-type ReviewReport struct {
-	GeneratedAt time.Time            `json:"generated_at"`
-	TimeRange   TimeRange            `json:"time_range"`
-	Activities  map[string]*Activity `json:"activities"`
-	Summary     *Summary             `json:"summary,omitempty"`
-}
-
-// CalculateSummary computes summary statistics from activities.
-func (r *ReviewReport) CalculateSummary() {
-	summary := &Summary{
-		ItemsByCategory: make(map[string]int),
-		ItemsByType:     make(map[string]int),
-	}
-
-	for _, act := range r.Activities {
-		for _, item := range act.Items {
-			summary.TotalItems++
-			summary.ItemsByCategory[string(item.Category)]++
-			summary.ItemsByType[item.Type]++
-		}
-	}
-
-	r.Summary = summary
-}
tools/review-tool/internal/config/config.go
@@ -1,173 +0,0 @@
-// Package config handles configuration loading and defaults.
-package config
-
-import (
-	"os"
-	"path/filepath"
-	"strings"
-
-	"gopkg.in/yaml.v3"
-)
-
-// Config represents the complete configuration.
-type Config struct {
-	User   UserConfig   `yaml:"user"`
-	GitHub GitHubConfig `yaml:"github"`
-	Org    OrgConfig    `yaml:"org"`
-	Jira   JiraConfig   `yaml:"jira"`
-	AI     AIConfig     `yaml:"ai"`
-	Output OutputConfig `yaml:"output"`
-}
-
-// UserConfig holds user identification.
-type UserConfig struct {
-	Name  string `yaml:"name"`
-	Email string `yaml:"email"`
-}
-
-// GitHubConfig configures the GitHub source.
-type GitHubConfig struct {
-	Enabled            bool     `yaml:"enabled"`
-	Username           string   `yaml:"username"`
-	Repos              []string `yaml:"repos,omitempty"`
-	IncludePRs         bool     `yaml:"include_prs"`
-	IncludeIssues      bool     `yaml:"include_issues"`
-	IncludeReviews     bool     `yaml:"include_reviews"`
-	IncludeCommits     bool     `yaml:"include_commits"`
-	IncludeDiscussions bool     `yaml:"include_discussions"`
-	IncludeComments    bool     `yaml:"include_comments"`
-}
-
-// OrgConfig configures the org-mode source.
-type OrgConfig struct {
-	Enabled             bool     `yaml:"enabled"`
-	Files               []string `yaml:"files"`
-	ArchiveDir          string   `yaml:"archive_dir,omitempty"` // Optional archive directory to scan
-	IncludeDone         bool     `yaml:"include_done"`
-	IncludeStateChanges bool     `yaml:"include_state_changes"`
-	IncludeClockEntries bool     `yaml:"include_clock_entries"`
-}
-
-// JiraConfig configures the Jira source.
-type JiraConfig struct {
-	Enabled  bool     `yaml:"enabled"`
-	Server   string   `yaml:"server"`
-	Projects []string `yaml:"projects,omitempty"`
-	Username string   `yaml:"username"`
-}
-
-// AIConfig configures the AI session history source (~/.local/share/ai).
-type AIConfig struct {
-	Enabled          bool   `yaml:"enabled"`
-	Dir              string `yaml:"dir"`
-	IncludeSessions  bool   `yaml:"include_sessions"`
-	IncludeLearnings bool   `yaml:"include_learnings"`
-	IncludeResearch  bool   `yaml:"include_research"`
-	IncludePlans     bool   `yaml:"include_plans"`
-}
-
-// OutputConfig configures output formatting.
-type OutputConfig struct {
-	DefaultFormat  string `yaml:"default_format"`
-	IncludeSummary bool   `yaml:"include_summary"`
-}
-
-// DefaultConfigPath returns the default config file location.
-func DefaultConfigPath() string {
-	home, _ := os.UserHomeDir()
-	return filepath.Join(home, ".config", "review-tool", "config.yaml")
-}
-
-// Load reads configuration from file, falling back to defaults.
-func Load(path string) (*Config, error) {
-	if path == "" {
-		path = DefaultConfigPath()
-	}
-
-	cfg := DefaultConfig()
-
-	data, err := os.ReadFile(path)
-	if err != nil {
-		if os.IsNotExist(err) {
-			return cfg, nil // Use defaults if no config file
-		}
-		return nil, err
-	}
-
-	if err := yaml.Unmarshal(data, cfg); err != nil {
-		return nil, err
-	}
-
-	// Expand ~ in paths
-	cfg.expandPaths()
-
-	return cfg, nil
-}
-
-// DefaultConfig returns a configuration with sensible defaults.
-func DefaultConfig() *Config {
-	home, _ := os.UserHomeDir()
-
-	return &Config{
-		User: UserConfig{},
-		GitHub: GitHubConfig{
-			Enabled:            true,
-			IncludePRs:         true,
-			IncludeIssues:      true,
-			IncludeReviews:     true,
-			IncludeCommits:     false,
-			IncludeDiscussions: true,
-			IncludeComments:    true,
-		},
-		Org: OrgConfig{
-			Enabled: true,
-			Files: []string{
-				filepath.Join(home, "desktop", "org", "todos.org"),
-			},
-			ArchiveDir:          filepath.Join(home, "desktop", "org", "archive"),
-			IncludeDone:         true,
-			IncludeStateChanges: true,
-			IncludeClockEntries: true,
-		},
-		Jira: JiraConfig{
-			Enabled: false,
-		},
-		AI: AIConfig{
-			Enabled:          true,
-			Dir:              filepath.Join(home, ".local", "share", "ai"),
-			IncludeSessions:  true,
-			IncludeLearnings: true,
-			IncludeResearch:  true,
-			IncludePlans:     true,
-		},
-		Output: OutputConfig{
-			DefaultFormat:  "markdown",
-			IncludeSummary: true,
-		},
-	}
-}
-
-func (c *Config) expandPaths() {
-	home, _ := os.UserHomeDir()
-
-	// Expand org files
-	for i, f := range c.Org.Files {
-		c.Org.Files[i] = expandHome(f, home)
-	}
-
-	// Expand org archive dir
-	c.Org.ArchiveDir = expandHome(c.Org.ArchiveDir, home)
-
-	// Expand AI dir
-	c.AI.Dir = expandHome(c.AI.Dir, home)
-}
-
-func expandHome(path, home string) string {
-	if strings.HasPrefix(path, "~/") {
-		return filepath.Join(home, path[2:])
-	}
-	if path == "~" {
-		return home
-	}
-	return path
-}
tools/review-tool/internal/filter/filter.go
@@ -1,124 +0,0 @@
-// Package filter provides post-fetch activity filtering.
-package filter
-
-import (
-	"strings"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-)
-
-// Filter defines include/exclude rules for activity items.
-type Filter struct {
-	// IncludeFolders keeps only items whose project/repository/directory
-	// matches one of these values (substring, case-insensitive).
-	// Empty means no include constraint.
-	IncludeFolders []string
-	// ExcludeFolders removes items whose project/repository/directory
-	// matches any of these values (substring, case-insensitive).
-	ExcludeFolders []string
-}
-
-// IsEmpty returns true if no filters are configured.
-func (f *Filter) IsEmpty() bool {
-	return len(f.IncludeFolders) == 0 && len(f.ExcludeFolders) == 0
-}
-
-// Apply filters a map of activities in place, removing non-matching items.
-func (f *Filter) Apply(activities map[string]*activity.Activity) {
-	if f.IsEmpty() {
-		return
-	}
-	for name, act := range activities {
-		activities[name] = &activity.Activity{
-			Source: act.Source,
-			Items:  f.FilterItems(act.Items),
-			Error:  act.Error,
-		}
-	}
-}
-
-// FilterItems returns only the items that pass the filter.
-func (f *Filter) FilterItems(items []activity.ActivityItem) []activity.ActivityItem {
-	if f.IsEmpty() {
-		return items
-	}
-	var result []activity.ActivityItem
-	for _, item := range items {
-		if f.Match(item) {
-			result = append(result, item)
-		}
-	}
-	return result
-}
-
-// Match returns true if an item passes the filter.
-func (f *Filter) Match(item activity.ActivityItem) bool {
-	folders := itemFolders(item)
-
-	// Items with no folder metadata (e.g. Jira issues) pass through
-	// exclude filters (they can't match) but are dropped by include
-	// filters (they can't satisfy the constraint).
-	if len(folders) == 0 {
-		return len(f.IncludeFolders) == 0
-	}
-
-	// Exclude check: if any folder matches an exclude pattern, reject
-	if len(f.ExcludeFolders) > 0 && matchesAny(folders, f.ExcludeFolders) {
-		return false
-	}
-
-	// Include check: at least one folder must match an include pattern
-	if len(f.IncludeFolders) > 0 {
-		return matchesAny(folders, f.IncludeFolders)
-	}
-
-	return true
-}
-
-// itemFolders extracts all folder-like values from an item's metadata.
-// It looks at project, repository, and directory fields.
-func itemFolders(item activity.ActivityItem) []string {
-	var folders []string
-	for _, key := range []string{"project", "repository", "directory"} {
-		if val, ok := item.Metadata[key]; ok && val != "" {
-			folders = append(folders, normalizePath(val))
-		}
-	}
-	return folders
-}
-
-// matchesAny returns true if any folder matches any pattern.
-// Matching is substring-based and case-insensitive.
-func matchesAny(folders []string, patterns []string) bool {
-	for _, folder := range folders {
-		for _, pattern := range patterns {
-			if containsFold(folder, normalizePath(pattern)) {
-				return true
-			}
-		}
-	}
-	return false
-}
-
-// normalizePath cleans a path for matching:
-// - strips trailing descriptions in parens: "~/src/home (homelab)" → "~/src/home"
-// - strips trailing whitespace
-// - strips trailing slashes
-func normalizePath(path string) string {
-	path = strings.TrimSpace(path)
-
-	// Strip parenthetical suffix: "~/src/home (homelab monorepo)" → "~/src/home"
-	if idx := strings.Index(path, " ("); idx > 0 {
-		path = path[:idx]
-	}
-
-	// Strip trailing slashes
-	path = strings.TrimRight(path, "/")
-
-	return path
-}
-
-// containsFold is a case-insensitive substring check.
-func containsFold(s, substr string) bool {
-	return strings.Contains(strings.ToLower(s), strings.ToLower(substr))
-}
tools/review-tool/internal/filter/filter_test.go
@@ -1,177 +0,0 @@
-package filter
-
-import (
-	"testing"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-)
-
-func item(meta map[string]string) activity.ActivityItem {
-	return activity.ActivityItem{
-		Title:    "test",
-		Metadata: meta,
-	}
-}
-
-func TestFilter_IncludeFolder(t *testing.T) {
-	f := &Filter{IncludeFolders: []string{"tektoncd"}}
-
-	tests := []struct {
-		name  string
-		item  activity.ActivityItem
-		match bool
-	}{
-		{"exact repo match", item(map[string]string{"repository": "tektoncd/pipeline"}), true},
-		{"project match", item(map[string]string{"project": "tektoncd/plumbing"}), true},
-		{"directory match", item(map[string]string{"directory": "~/src/tektoncd/pipeline"}), true},
-		{"no match", item(map[string]string{"project": "~/src/home"}), false},
-		{"no metadata", item(map[string]string{}), false},
-		{"case insensitive", item(map[string]string{"project": "TektonCD/Pipeline"}), true},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := f.Match(tt.item); got != tt.match {
-				t.Errorf("Match() = %v, want %v", got, tt.match)
-			}
-		})
-	}
-}
-
-func TestFilter_ExcludeFolder(t *testing.T) {
-	f := &Filter{ExcludeFolders: []string{"home"}}
-
-	tests := []struct {
-		name  string
-		item  activity.ActivityItem
-		match bool
-	}{
-		{"excludes home project", item(map[string]string{"project": "~/src/home (homelab)"}), false},
-		{"excludes home dir", item(map[string]string{"directory": "~/src/home"}), false},
-		{"keeps tektoncd", item(map[string]string{"project": "tektoncd/pipeline"}), true},
-		{"no metadata passes through", item(map[string]string{}), true},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := f.Match(tt.item); got != tt.match {
-				t.Errorf("Match() = %v, want %v", got, tt.match)
-			}
-		})
-	}
-}
-
-func TestFilter_IncludeAndExclude(t *testing.T) {
-	// Include tektoncd but exclude tektoncd/plumbing
-	f := &Filter{
-		IncludeFolders: []string{"tektoncd"},
-		ExcludeFolders: []string{"tektoncd/plumbing"},
-	}
-
-	tests := []struct {
-		name  string
-		item  activity.ActivityItem
-		match bool
-	}{
-		{"includes pipeline", item(map[string]string{"project": "tektoncd/pipeline"}), true},
-		{"excludes plumbing", item(map[string]string{"project": "tektoncd/plumbing"}), false},
-		{"excludes non-tektoncd", item(map[string]string{"project": "~/src/home"}), false},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := f.Match(tt.item); got != tt.match {
-				t.Errorf("Match() = %v, want %v", got, tt.match)
-			}
-		})
-	}
-}
-
-func TestFilter_NormalizePath(t *testing.T) {
-	tests := []struct {
-		input string
-		want  string
-	}{
-		{"~/src/home (homelab)", "~/src/home"},
-		{"~/src/home (homelab monorepo)", "~/src/home"},
-		{"tektoncd/pipeline", "tektoncd/pipeline"},
-		{"  ~/src/home/  ", "~/src/home"},
-		{"home", "home"},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.input, func(t *testing.T) {
-			if got := normalizePath(tt.input); got != tt.want {
-				t.Errorf("normalizePath(%q) = %q, want %q", tt.input, got, tt.want)
-			}
-		})
-	}
-}
-
-func TestFilter_Apply(t *testing.T) {
-	f := &Filter{IncludeFolders: []string{"tektoncd"}}
-
-	activities := map[string]*activity.Activity{
-		"ai": {
-			Source: "ai",
-			Items: []activity.ActivityItem{
-				item(map[string]string{"project": "tektoncd/pipeline"}),
-				item(map[string]string{"project": "~/src/home"}),
-				item(map[string]string{"project": "tektoncd/plumbing"}),
-			},
-		},
-		"github": {
-			Source: "github",
-			Items: []activity.ActivityItem{
-				item(map[string]string{"repository": "tektoncd/pipeline"}),
-				item(map[string]string{"repository": "vdemeester/home"}),
-			},
-		},
-	}
-
-	f.Apply(activities)
-
-	if len(activities["ai"].Items) != 2 {
-		t.Errorf("ai items = %d, want 2", len(activities["ai"].Items))
-	}
-	if len(activities["github"].Items) != 1 {
-		t.Errorf("github items = %d, want 1", len(activities["github"].Items))
-	}
-}
-
-func TestFilter_Empty(t *testing.T) {
-	f := &Filter{}
-
-	if !f.IsEmpty() {
-		t.Error("expected empty filter")
-	}
-
-	// Empty filter should pass everything
-	i := item(map[string]string{"project": "anything"})
-	if !f.Match(i) {
-		t.Error("empty filter should match everything")
-	}
-}
-
-func TestFilter_MultipleIncludeFolders(t *testing.T) {
-	// Either tektoncd or chisel
-	f := &Filter{IncludeFolders: []string{"tektoncd", "chisel"}}
-
-	tests := []struct {
-		name  string
-		item  activity.ActivityItem
-		match bool
-	}{
-		{"tektoncd matches", item(map[string]string{"project": "tektoncd/pipeline"}), true},
-		{"chisel matches", item(map[string]string{"project": "github.com/vdemeester/chisel"}), true},
-		{"home excluded", item(map[string]string{"project": "~/src/home"}), false},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := f.Match(tt.item); got != tt.match {
-				t.Errorf("Match() = %v, want %v", got, tt.match)
-			}
-		})
-	}
-}
tools/review-tool/internal/output/json.go
@@ -1,15 +0,0 @@
-package output
-
-import (
-	"encoding/json"
-	"io"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-)
-
-// WriteJSON writes the report in JSON format.
-func WriteJSON(w io.Writer, report *activity.ReviewReport) error {
-	encoder := json.NewEncoder(w)
-	encoder.SetIndent("", "  ")
-	return encoder.Encode(report)
-}
tools/review-tool/internal/output/json_test.go
@@ -1,76 +0,0 @@
-package output
-
-import (
-	"bytes"
-	"encoding/json"
-	"testing"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-)
-
-func TestWriteJSON_ValidOutput(t *testing.T) {
-	report := &activity.ReviewReport{
-		GeneratedAt: time.Date(2026, 1, 27, 15, 30, 0, 0, time.UTC),
-		TimeRange: activity.TimeRange{
-			Start:       time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC),
-			End:         time.Date(2026, 1, 27, 0, 0, 0, 0, time.UTC),
-			Description: "last week",
-		},
-		Activities: map[string]*activity.Activity{
-			"github": {
-				Source: "github",
-				Items: []activity.ActivityItem{
-					{
-						ID:       "1",
-						Title:    "Test PR",
-						Type:     "pr_merged",
-						Category: activity.CategoryGitHub,
-					},
-				},
-			},
-		},
-	}
-
-	var buf bytes.Buffer
-	err := WriteJSON(&buf, report)
-	if err != nil {
-		t.Fatalf("WriteJSON() error = %v", err)
-	}
-
-	// Verify it's valid JSON
-	var parsed activity.ReviewReport
-	if err := json.Unmarshal(buf.Bytes(), &parsed); err != nil {
-		t.Fatalf("output is not valid JSON: %v", err)
-	}
-
-	if parsed.TimeRange.Description != "last week" {
-		t.Errorf("parsed description = %q, want %q", parsed.TimeRange.Description, "last week")
-	}
-
-	if len(parsed.Activities["github"].Items) != 1 {
-		t.Errorf("parsed activities count = %d, want 1", len(parsed.Activities["github"].Items))
-	}
-}
-
-func TestWriteJSON_Indented(t *testing.T) {
-	report := &activity.ReviewReport{
-		GeneratedAt: time.Now(),
-		TimeRange: activity.TimeRange{
-			Description: "today",
-		},
-		Activities: make(map[string]*activity.Activity),
-	}
-
-	var buf bytes.Buffer
-	err := WriteJSON(&buf, report)
-	if err != nil {
-		t.Fatalf("WriteJSON() error = %v", err)
-	}
-
-	// Check that output is indented (contains newlines and spaces)
-	output := buf.String()
-	if !bytes.Contains(buf.Bytes(), []byte("\n  ")) {
-		t.Errorf("output should be indented, got:\n%s", output)
-	}
-}
tools/review-tool/internal/output/markdown.go
@@ -1,156 +0,0 @@
-// Package output provides report formatting.
-package output
-
-import (
-	"fmt"
-	"io"
-	"sort"
-	"strings"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-)
-
-// WriteMarkdown writes the report in markdown format.
-func WriteMarkdown(w io.Writer, report *activity.ReviewReport) error {
-	fmt.Fprintf(w, "# Activity Review: %s\n\n", report.TimeRange.Description)
-	fmt.Fprintf(w, "**Period:** %s to %s\n",
-		report.TimeRange.Start.Format("2006-01-02"),
-		report.TimeRange.End.Format("2006-01-02"))
-	fmt.Fprintf(w, "**Generated:** %s\n\n", report.GeneratedAt.Format("2006-01-02 15:04"))
-
-	// Summary section
-	if report.Summary != nil && report.Summary.TotalItems > 0 {
-		fmt.Fprintln(w, "## Summary")
-		fmt.Fprintf(w, "- **Total activities:** %d\n", report.Summary.TotalItems)
-
-		// Sort categories for consistent output
-		cats := make([]string, 0, len(report.Summary.ItemsByCategory))
-		for cat := range report.Summary.ItemsByCategory {
-			cats = append(cats, cat)
-		}
-		sort.Strings(cats)
-
-		for _, cat := range cats {
-			fmt.Fprintf(w, "- **%s:** %d\n", strings.Title(cat), report.Summary.ItemsByCategory[cat])
-		}
-		fmt.Fprintln(w)
-	}
-
-	// Activities by source
-	sourceOrder := []string{"github", "org", "jira", "ai"}
-	for _, source := range sourceOrder {
-		act, ok := report.Activities[source]
-		if !ok || len(act.Items) == 0 {
-			continue
-		}
-
-		fmt.Fprintf(w, "## %s\n\n", formatSourceName(source))
-
-		if act.Error != "" {
-			fmt.Fprintf(w, "> Error: %s\n\n", act.Error)
-			continue
-		}
-
-		// Group by type
-		byType := groupByType(act.Items)
-		types := make([]string, 0, len(byType))
-		for t := range byType {
-			types = append(types, t)
-		}
-		sort.Strings(types)
-
-		for _, typ := range types {
-			items := byType[typ]
-			fmt.Fprintf(w, "### %s (%d)\n\n", formatTypeName(typ), len(items))
-
-			// Sort by timestamp descending
-			sort.Slice(items, func(i, j int) bool {
-				return items[i].Timestamp.After(items[j].Timestamp)
-			})
-
-			for _, item := range items {
-				writeMarkdownItem(w, item)
-			}
-			fmt.Fprintln(w)
-		}
-	}
-
-	return nil
-}
-
-func writeMarkdownItem(w io.Writer, item activity.ActivityItem) {
-	timestamp := item.Timestamp.Format("2006-01-02 15:04")
-	if item.URL != "" {
-		fmt.Fprintf(w, "- [%s](%s) (%s)\n", item.Title, item.URL, timestamp)
-	} else {
-		fmt.Fprintf(w, "- %s (%s)\n", item.Title, timestamp)
-	}
-
-	// Show metadata for org items
-	if item.Category == activity.CategoryOrg {
-		var meta []string
-		if section := item.Metadata["section"]; section != "" {
-			meta = append(meta, section)
-		}
-		if file := item.Metadata["file"]; file != "" && !strings.HasSuffix(file, "todos.org") {
-			// Show shortened file path for archive items
-			if strings.Contains(file, "/archive/") {
-				parts := strings.Split(file, "/archive/")
-				if len(parts) > 1 {
-					meta = append(meta, "archive/"+parts[1])
-				}
-			}
-		}
-		if len(meta) > 0 {
-			fmt.Fprintf(w, "  _(%s)_\n", strings.Join(meta, " | "))
-		}
-	}
-
-	if item.Description != "" {
-		fmt.Fprintf(w, "  > %s\n", item.Description)
-	}
-}
-
-func groupByType(items []activity.ActivityItem) map[string][]activity.ActivityItem {
-	result := make(map[string][]activity.ActivityItem)
-	for _, item := range items {
-		result[item.Type] = append(result[item.Type], item)
-	}
-	return result
-}
-
-func formatSourceName(source string) string {
-	names := map[string]string{
-		"github": "GitHub",
-		"org":    "Org-mode",
-		"jira":   "Jira",
-		"ai":     "AI Sessions",
-	}
-	if name, ok := names[source]; ok {
-		return name
-	}
-	return strings.Title(source)
-}
-
-func formatTypeName(typ string) string {
-	names := map[string]string{
-		"pr_merged":          "PRs Merged",
-		"pr_reviewed":        "PRs Reviewed",
-		"issue_created":      "Issues Created",
-		"issue_closed":       "Issues Closed",
-		"issue_updated":      "Issues Updated",
-		"comment":            "Comments",
-		"discussion":         "Discussions Started",
-		"discussion_comment": "Discussion Comments",
-		"todo_done":          "Tasks Completed",
-		"state_change":       "State Changes",
-		"clock_entry":        "Time Logged",
-		"session":            "Sessions",
-		"learning":           "Learnings",
-		"research":           "Research",
-	}
-	if name, ok := names[typ]; ok {
-		return name
-	}
-	return strings.Title(strings.ReplaceAll(typ, "_", " "))
-}
tools/review-tool/internal/output/markdown_test.go
@@ -1,153 +0,0 @@
-package output
-
-import (
-	"bytes"
-	"strings"
-	"testing"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-)
-
-func TestWriteMarkdown_Header(t *testing.T) {
-	report := &activity.ReviewReport{
-		GeneratedAt: time.Date(2026, 1, 27, 15, 30, 0, 0, time.UTC),
-		TimeRange: activity.TimeRange{
-			Start:       time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC),
-			End:         time.Date(2026, 1, 27, 0, 0, 0, 0, time.UTC),
-			Description: "last week",
-		},
-		Activities: make(map[string]*activity.Activity),
-	}
-
-	var buf bytes.Buffer
-	err := WriteMarkdown(&buf, report)
-	if err != nil {
-		t.Fatalf("WriteMarkdown() error = %v", err)
-	}
-
-	output := buf.String()
-	if !strings.Contains(output, "# Activity Review: last week") {
-		t.Errorf("missing title header, got:\n%s", output)
-	}
-	if !strings.Contains(output, "**Period:** 2026-01-20 to 2026-01-27") {
-		t.Errorf("missing period, got:\n%s", output)
-	}
-}
-
-func TestWriteMarkdown_WithSummary(t *testing.T) {
-	report := &activity.ReviewReport{
-		GeneratedAt: time.Now(),
-		TimeRange: activity.TimeRange{
-			Start:       time.Now().AddDate(0, 0, -7),
-			End:         time.Now(),
-			Description: "last week",
-		},
-		Activities: make(map[string]*activity.Activity),
-		Summary: &activity.Summary{
-			TotalItems:      5,
-			ItemsByCategory: map[string]int{"github": 3, "org": 2},
-			ItemsByType:     map[string]int{"pr_merged": 3, "todo_done": 2},
-		},
-	}
-
-	var buf bytes.Buffer
-	err := WriteMarkdown(&buf, report)
-	if err != nil {
-		t.Fatalf("WriteMarkdown() error = %v", err)
-	}
-
-	output := buf.String()
-	if !strings.Contains(output, "## Summary") {
-		t.Errorf("missing summary section, got:\n%s", output)
-	}
-	if !strings.Contains(output, "**Total activities:** 5") {
-		t.Errorf("missing total count, got:\n%s", output)
-	}
-}
-
-func TestWriteMarkdown_WithActivities(t *testing.T) {
-	report := &activity.ReviewReport{
-		GeneratedAt: time.Now(),
-		TimeRange: activity.TimeRange{
-			Start:       time.Now().AddDate(0, 0, -7),
-			End:         time.Now(),
-			Description: "last week",
-		},
-		Activities: map[string]*activity.Activity{
-			"github": {
-				Source: "github",
-				Items: []activity.ActivityItem{
-					{
-						ID:        "1",
-						Title:     "Fix authentication bug",
-						Type:      "pr_merged",
-						Category:  activity.CategoryGitHub,
-						Timestamp: time.Now(),
-						URL:       "https://github.com/org/repo/pull/123",
-					},
-				},
-			},
-		},
-	}
-
-	var buf bytes.Buffer
-	err := WriteMarkdown(&buf, report)
-	if err != nil {
-		t.Fatalf("WriteMarkdown() error = %v", err)
-	}
-
-	output := buf.String()
-	if !strings.Contains(output, "## GitHub") {
-		t.Errorf("missing GitHub section, got:\n%s", output)
-	}
-	if !strings.Contains(output, "Fix authentication bug") {
-		t.Errorf("missing activity item, got:\n%s", output)
-	}
-	if !strings.Contains(output, "https://github.com/org/repo/pull/123") {
-		t.Errorf("missing URL, got:\n%s", output)
-	}
-}
-
-func TestFormatSourceName(t *testing.T) {
-	tests := []struct {
-		source string
-		want   string
-	}{
-		{"github", "GitHub"},
-		{"org", "Org-mode"},
-		{"jira", "Jira"},
-		{"ai", "AI Sessions"},
-		{"unknown", "Unknown"},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.source, func(t *testing.T) {
-			got := formatSourceName(tt.source)
-			if got != tt.want {
-				t.Errorf("formatSourceName(%q) = %q, want %q", tt.source, got, tt.want)
-			}
-		})
-	}
-}
-
-func TestFormatTypeName(t *testing.T) {
-	tests := []struct {
-		typ  string
-		want string
-	}{
-		{"pr_merged", "PRs Merged"},
-		{"todo_done", "Tasks Completed"},
-		{"session", "Sessions"},
-		{"custom_type", "Custom Type"},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.typ, func(t *testing.T) {
-			got := formatTypeName(tt.typ)
-			if got != tt.want {
-				t.Errorf("formatTypeName(%q) = %q, want %q", tt.typ, got, tt.want)
-			}
-		})
-	}
-}
tools/review-tool/internal/output/yaml.go
@@ -1,123 +0,0 @@
-package output
-
-import (
-	"fmt"
-	"io"
-	"sort"
-	"strings"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-)
-
-// WriteYAML writes the report in YAML format optimized for LLM consumption.
-// YAML format provides better accuracy for LLM understanding compared to JSON or XML.
-func WriteYAML(w io.Writer, report *activity.ReviewReport) error {
-	fmt.Fprintf(w, "# Activity Review: %s\n", report.TimeRange.Description)
-	fmt.Fprintf(w, "period:\n")
-	fmt.Fprintf(w, "  start: %s\n", report.TimeRange.Start.Format("2006-01-02"))
-	fmt.Fprintf(w, "  end: %s\n", report.TimeRange.End.Format("2006-01-02"))
-	fmt.Fprintf(w, "generated: %s\n", report.GeneratedAt.Format("2006-01-02 15:04"))
-	fmt.Fprintln(w)
-
-	// Summary
-	if report.Summary != nil && report.Summary.TotalItems > 0 {
-		fmt.Fprintln(w, "summary:")
-		fmt.Fprintf(w, "  total_activities: %d\n", report.Summary.TotalItems)
-
-		cats := make([]string, 0, len(report.Summary.ItemsByCategory))
-		for cat := range report.Summary.ItemsByCategory {
-			cats = append(cats, cat)
-		}
-		sort.Strings(cats)
-
-		fmt.Fprintln(w, "  by_category:")
-		for _, cat := range cats {
-			fmt.Fprintf(w, "    %s: %d\n", cat, report.Summary.ItemsByCategory[cat])
-		}
-		fmt.Fprintln(w)
-	}
-
-	// Activities by source
-	fmt.Fprintln(w, "activities:")
-	sourceOrder := []string{"github", "org", "jira", "ai"}
-	for _, source := range sourceOrder {
-		act, ok := report.Activities[source]
-		if !ok || len(act.Items) == 0 {
-			continue
-		}
-
-		fmt.Fprintf(w, "  %s:\n", source)
-
-		if act.Error != "" {
-			fmt.Fprintf(w, "    error: %q\n", act.Error)
-			continue
-		}
-
-		// Group by type
-		byType := groupByType(act.Items)
-		types := make([]string, 0, len(byType))
-		for t := range byType {
-			types = append(types, t)
-		}
-		sort.Strings(types)
-
-		for _, typ := range types {
-			items := byType[typ]
-			fmt.Fprintf(w, "    %s:\n", typ)
-
-			// Sort by timestamp descending
-			sort.Slice(items, func(i, j int) bool {
-				return items[i].Timestamp.After(items[j].Timestamp)
-			})
-
-			for _, item := range items {
-				writeYAMLItem(w, item)
-			}
-		}
-	}
-
-	return nil
-}
-
-func writeYAMLItem(w io.Writer, item activity.ActivityItem) {
-	// Escape title for YAML if needed
-	title := item.Title
-	if strings.ContainsAny(title, ":\n\"'") {
-		title = fmt.Sprintf("%q", title)
-	}
-
-	fmt.Fprintf(w, "      - title: %s\n", title)
-	fmt.Fprintf(w, "        timestamp: %s\n", item.Timestamp.Format("2006-01-02 15:04"))
-
-	if item.URL != "" {
-		fmt.Fprintf(w, "        url: %s\n", item.URL)
-	}
-
-	// Include relevant metadata
-	if section := item.Metadata["section"]; section != "" {
-		fmt.Fprintf(w, "        section: %s\n", section)
-	}
-	if file := item.Metadata["file"]; file != "" {
-		// Shorten archive paths
-		if strings.Contains(file, "/archive/") {
-			parts := strings.Split(file, "/archive/")
-			if len(parts) > 1 {
-				fmt.Fprintf(w, "        source: archive/%s\n", parts[1])
-			}
-		}
-	}
-	if duration := item.Metadata["duration"]; duration != "" {
-		fmt.Fprintf(w, "        duration: %s\n", duration)
-	}
-	if repo := item.Metadata["repo"]; repo != "" {
-		fmt.Fprintf(w, "        repo: %s\n", repo)
-	}
-
-	if item.Description != "" {
-		desc := item.Description
-		if strings.ContainsAny(desc, ":\n\"'") {
-			desc = fmt.Sprintf("%q", desc)
-		}
-		fmt.Fprintf(w, "        description: %s\n", desc)
-	}
-}
tools/review-tool/internal/sources/ai.go
@@ -1,280 +0,0 @@
-package sources
-
-import (
-	"bufio"
-	"context"
-	"os"
-	"path/filepath"
-	"regexp"
-	"strings"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-var (
-	// **Date:** 2026-01-21
-	mdDateRe = regexp.MustCompile(`\*\*Date:\*\*\s+(\d{4}-\d{2}-\d{2})`)
-	// # Title or # Some Title Here
-	mdTitleRe = regexp.MustCompile(`^#\s+(.+)$`)
-	// #+title: SelfCI Analysis
-	orgTitleRe = regexp.MustCompile(`^\s*#\+title:\s*(.+)$`)
-	// #+date: [2026-01-16 Thu]
-	orgDateRe = regexp.MustCompile(`^\s*#\+date:\s*\[(\d{4}-\d{2}-\d{2})[^\]]*\]`)
-	// Filename patterns: 2026-01-21-something.md or 20260121-something.md
-	filenameDateRe        = regexp.MustCompile(`^(\d{4}-\d{2}-\d{2})`)
-	filenameDateCompactRe = regexp.MustCompile(`^(\d{8})`)
-	// **Key:** value or **Key**: value (with optional trailing **)
-	// Captures key and value from markdown bold metadata lines
-	mdMetadataRe = regexp.MustCompile(`^\*\*([A-Za-z][A-Za-z ]*?)\*?\*?:\*?\*?\s*(.+)$`)
-)
-
-// AISource fetches activity from AI session history (~/.local/share/ai).
-type AISource struct {
-	cfg *config.AIConfig
-}
-
-// NewAISource creates a new AI history source.
-func NewAISource(cfg *config.AIConfig) *AISource {
-	return &AISource{cfg: cfg}
-}
-
-// Name returns the source identifier.
-func (s *AISource) Name() string {
-	return "ai"
-}
-
-// Validate checks if the base directory exists.
-func (s *AISource) Validate() error {
-	if _, err := os.Stat(s.cfg.Dir); err != nil {
-		return err
-	}
-	return nil
-}
-
-// Fetch retrieves AI session activities within the time range.
-func (s *AISource) Fetch(ctx context.Context, start, end time.Time) (*activity.Activity, error) {
-	act := &activity.Activity{
-		Source: "ai",
-		Items:  []activity.ActivityItem{},
-	}
-
-	if s.cfg.IncludeSessions {
-		items, err := s.scanDirectory(filepath.Join(s.cfg.Dir, "sessions"), "session", start, end)
-		if err == nil {
-			act.Items = append(act.Items, items...)
-		}
-	}
-
-	if s.cfg.IncludeLearnings {
-		items, err := s.scanDirectory(filepath.Join(s.cfg.Dir, "learnings"), "learning", start, end)
-		if err == nil {
-			act.Items = append(act.Items, items...)
-		}
-	}
-
-	if s.cfg.IncludeResearch {
-		items, err := s.scanDirectory(filepath.Join(s.cfg.Dir, "research"), "research", start, end)
-		if err == nil {
-			act.Items = append(act.Items, items...)
-		}
-	}
-
-	if s.cfg.IncludePlans {
-		items, err := s.scanDirectory(filepath.Join(s.cfg.Dir, "plans"), "plan", start, end)
-		if err == nil {
-			act.Items = append(act.Items, items...)
-		}
-	}
-
-	return act, nil
-}
-
-func (s *AISource) scanDirectory(baseDir, itemType string, start, end time.Time) ([]activity.ActivityItem, error) {
-	var items []activity.ActivityItem
-
-	// Resolve symlinks so filepath.Walk can traverse symlinked directories
-	// (e.g. home-manager managed paths via nix store)
-	resolvedDir, err := filepath.EvalSymlinks(baseDir)
-	if err != nil {
-		resolvedDir = baseDir // Fall back to original if resolution fails
-	}
-
-	// Walk through YYYY-MM subdirectories
-	err = filepath.Walk(resolvedDir, func(path string, info os.FileInfo, err error) error {
-		if err != nil {
-			return nil // Skip errors, continue walking
-		}
-
-		if info.IsDir() {
-			return nil
-		}
-
-		// Only process .md and .org files
-		ext := strings.ToLower(filepath.Ext(path))
-		if ext != ".md" && ext != ".org" {
-			return nil
-		}
-
-		// Skip small files (likely not content files)
-		if info.Size() < 50 {
-			return nil
-		}
-
-		item, err := s.parseFile(path, itemType, ext, info.ModTime())
-		if err != nil {
-			return nil // Skip files that fail to parse
-		}
-
-		// Filter by date range
-		if item.Timestamp.Before(start) || item.Timestamp.After(end) {
-			return nil
-		}
-
-		items = append(items, *item)
-		return nil
-	})
-
-	return items, err
-}
-
-func (s *AISource) parseFile(path, itemType, ext string, modTime time.Time) (*activity.ActivityItem, error) {
-	file, err := os.Open(path)
-	if err != nil {
-		return nil, err
-	}
-	defer file.Close()
-
-	var title string
-	var dateStr string
-	metadata := map[string]string{"path": path}
-	filename := filepath.Base(path)
-
-	scanner := bufio.NewScanner(file)
-	lineCount := 0
-	for scanner.Scan() && lineCount < 40 {
-		line := scanner.Text()
-		lineCount++
-
-		// Parse based on file type
-		if ext == ".org" {
-			if matches := orgTitleRe.FindStringSubmatch(line); len(matches) > 1 && title == "" {
-				title = strings.TrimSpace(matches[1])
-			}
-			if matches := orgDateRe.FindStringSubmatch(line); len(matches) > 1 && dateStr == "" {
-				dateStr = matches[1]
-			}
-		} else {
-			// Markdown title
-			if matches := mdTitleRe.FindStringSubmatch(line); len(matches) > 1 && title == "" {
-				title = strings.TrimSpace(matches[1])
-			}
-			// Extract **Key:** value metadata
-			if matches := mdMetadataRe.FindStringSubmatch(line); len(matches) > 2 {
-				key := strings.ToLower(strings.TrimSpace(matches[1]))
-				val := cleanMetadataValue(matches[2])
-				switch key {
-				case "date":
-					if dateStr == "" {
-						// Extract YYYY-MM-DD from various date formats
-						if d := extractDate(val); d != "" {
-							dateStr = d
-						}
-					}
-				case "project":
-					metadata["project"] = val
-				case "repository", "repositories", "repo":
-					metadata["repository"] = val
-				case "directory", "working directory":
-					metadata["directory"] = val
-				case "tool":
-					metadata["tool"] = val
-				case "tags":
-					metadata["tags"] = val
-				case "host":
-					metadata["host"] = val
-				}
-			}
-		}
-	}
-
-	// Fallback: extract date from filename
-	if dateStr == "" {
-		if matches := filenameDateRe.FindStringSubmatch(filename); len(matches) > 1 {
-			dateStr = matches[1]
-		} else if matches := filenameDateCompactRe.FindStringSubmatch(filename); len(matches) > 1 {
-			d := matches[1]
-			dateStr = d[:4] + "-" + d[4:6] + "-" + d[6:8]
-		}
-	}
-
-	// Fallback title: use filename without extension and date prefix
-	if title == "" {
-		title = cleanFilename(filename)
-	}
-
-	// Parse date: content > filename > file modification time
-	ts := modTime
-	if dateStr != "" {
-		if parsed, err := time.Parse("2006-01-02", dateStr); err == nil {
-			ts = parsed
-		}
-	}
-
-	return &activity.ActivityItem{
-		ID:        path,
-		Title:     title,
-		Type:      itemType,
-		Category:  activity.CategoryAI,
-		Timestamp: ts,
-		Metadata:  metadata,
-	}, nil
-}
-
-// cleanMetadataValue strips markdown formatting from a metadata value.
-// Removes backticks, trailing parenthetical descriptions, etc.
-func cleanMetadataValue(val string) string {
-	val = strings.TrimSpace(val)
-	// Strip backticks
-	val = strings.ReplaceAll(val, "`", "")
-	return val
-}
-
-// extractDate pulls a YYYY-MM-DD date from various formats:
-// "2026-01-21", "January 21, 2026", "February 18, 2026"
-func extractDate(val string) string {
-	// Direct YYYY-MM-DD
-	if m := filenameDateRe.FindString(val); m != "" {
-		return m
-	}
-	// Try standard Go date parsing for verbose formats
-	for _, layout := range []string{"January 2, 2006", "January 02, 2006", "Jan 2, 2006"} {
-		if t, err := time.Parse(layout, strings.TrimSpace(val)); err == nil {
-			return t.Format("2006-01-02")
-		}
-	}
-	return ""
-}
-
-func cleanFilename(filename string) string {
-	// Remove extension
-	name := strings.TrimSuffix(filename, filepath.Ext(filename))
-
-	// Remove date prefixes
-	name = filenameDateRe.ReplaceAllString(name, "")
-	name = filenameDateCompactRe.ReplaceAllString(name, "")
-
-	// Remove common suffixes
-	name = strings.TrimPrefix(name, "-")
-	name = strings.TrimPrefix(name, "_")
-
-	// Convert underscores and hyphens to spaces, title case
-	name = strings.ReplaceAll(name, "-", " ")
-	name = strings.ReplaceAll(name, "_", " ")
-
-	// Remove timestamp patterns like 145851_SESSION_
-	name = regexp.MustCompile(`^\d{6}_\w+_`).ReplaceAllString(name, "")
-
-	return strings.TrimSpace(name)
-}
tools/review-tool/internal/sources/ai_integration_test.go
@@ -1,54 +0,0 @@
-package sources
-
-import (
-	"context"
-	"os"
-	"path/filepath"
-	"testing"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-func TestAISource_RealHistory(t *testing.T) {
-	home, _ := os.UserHomeDir()
-	aiDir := filepath.Join(home, ".local", "share", "ai")
-
-	if _, err := os.Stat(aiDir); err != nil {
-		t.Skipf("AI history not found at %s", aiDir)
-	}
-
-	cfg := &config.AIConfig{
-		Enabled:          true,
-		Dir:              aiDir,
-		IncludeSessions:  true,
-		IncludeLearnings: true,
-		IncludeResearch:  true,
-		IncludePlans:     true,
-	}
-
-	source := NewAISource(cfg)
-
-	// Last 7 days
-	now := time.Now()
-	start := time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, now.Location())
-
-	t.Logf("Range: %s to %s", start.Format("2006-01-02"), now.Format("2006-01-02"))
-
-	act, err := source.Fetch(context.Background(), start, now)
-	if err != nil {
-		t.Fatalf("Fetch error: %v", err)
-	}
-
-	t.Logf("Found %d items", len(act.Items))
-	for i, item := range act.Items {
-		if i < 10 {
-			t.Logf("  [%s] %s (%s)", item.Type, item.Title, item.Timestamp.Format("2006-01-02"))
-		}
-	}
-
-	// Should find at least some items in the last 7 days
-	if len(act.Items) == 0 {
-		t.Error("Expected to find some AI history items")
-	}
-}
tools/review-tool/internal/sources/ai_test.go
@@ -1,446 +0,0 @@
-package sources
-
-import (
-	"os"
-	"path/filepath"
-	"testing"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-// Helper to create temp directory with test files
-func setupTestAIDir(t *testing.T) string {
-	t.Helper()
-	dir := t.TempDir()
-
-	// Create directory structure
-	sessionsDir := filepath.Join(dir, "sessions", "2026-01")
-	learningsDir := filepath.Join(dir, "learnings", "2026-01")
-	researchDir := filepath.Join(dir, "research", "2026-01")
-
-	for _, d := range []string{sessionsDir, learningsDir, researchDir} {
-		if err := os.MkdirAll(d, 0o755); err != nil {
-			t.Fatalf("failed to create dir: %v", err)
-		}
-	}
-
-	// Create test session file with metadata
-	sessionContent := `# Terraform Branch Protection Implementation
-
-**Date:** 2026-01-21
-**Repository:** tektoncd/plumbing
-**Duration:** ~3 hours
-
-## Summary
-Implemented branch protection automation.
-`
-	if err := os.WriteFile(filepath.Join(sessionsDir, "2026-01-21-terraform-session.md"), []byte(sessionContent), 0o644); err != nil {
-		t.Fatalf("failed to write session file: %v", err)
-	}
-
-	// Create session file without explicit date (date from filename)
-	sessionNoDate := `# Mobile Development Planning
-
-## Summary
-Discussed mobile dev workflow.
-`
-	if err := os.WriteFile(filepath.Join(sessionsDir, "2026-01-15-mobile-planning.md"), []byte(sessionNoDate), 0o644); err != nil {
-		t.Fatalf("failed to write session file: %v", err)
-	}
-
-	// Create learning file
-	learningContent := `# SSH Config Required for Non-Standard Keys
-
-**Date:** 2026-01-18
-**Duration:** ~45 minutes
-**Commit:** adf33b32
-
-## Problem
-SSH authentication failing with custom key paths.
-
-## Solution
-Added proper Host blocks to ~/.ssh/config.
-`
-	if err := os.WriteFile(filepath.Join(learningsDir, "2026-01-18-ssh-config-learning.md"), []byte(learningContent), 0o644); err != nil {
-		t.Fatalf("failed to write learning file: %v", err)
-	}
-
-	// Create research file (org-mode)
-	researchContent := `#+title: SelfCI Analysis
-#+date: [2026-01-16 Thu]
-#+filetags: :ci:research:
-
-* Summary
-Research on local CI systems.
-`
-	if err := os.WriteFile(filepath.Join(researchDir, "selfci-analysis.org"), []byte(researchContent), 0o644); err != nil {
-		t.Fatalf("failed to write research file: %v", err)
-	}
-
-	return dir
-}
-
-func TestAISource_ParsesSessionWithMetadata(t *testing.T) {
-	aiDir := setupTestAIDir(t)
-
-	cfg := &config.AIConfig{
-		Enabled:          true,
-		Dir:              aiDir,
-		IncludeSessions:  true,
-		IncludeLearnings: false,
-		IncludeResearch:  false,
-	}
-
-	source := NewAISource(cfg)
-
-	if source.Name() != "ai" {
-		t.Errorf("Name() = %q, want %q", source.Name(), "ai")
-	}
-
-	// Query for January 2026
-	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	if len(act.Items) == 0 {
-		t.Fatal("expected at least one session item")
-	}
-
-	if act.Source != "ai" {
-		t.Errorf("Source = %q, want %q", act.Source, "ai")
-	}
-
-	// Find the terraform session
-	var found bool
-	for _, item := range act.Items {
-		if item.Title == "Terraform Branch Protection Implementation" {
-			found = true
-			if item.Type != "session" {
-				t.Errorf("Type = %q, want %q", item.Type, "session")
-			}
-			// Date should be 2026-01-21
-			if item.Timestamp.Day() != 21 {
-				t.Errorf("Timestamp day = %d, want 21", item.Timestamp.Day())
-			}
-		}
-	}
-
-	if !found {
-		t.Error("terraform session not found in items")
-	}
-}
-
-func TestAISource_ParsesDateFromFilename(t *testing.T) {
-	aiDir := setupTestAIDir(t)
-
-	cfg := &config.AIConfig{
-		Enabled:          true,
-		Dir:              aiDir,
-		IncludeSessions:  true,
-		IncludeLearnings: false,
-		IncludeResearch:  false,
-	}
-
-	source := NewAISource(cfg)
-
-	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	// Find mobile planning session (no explicit date in content)
-	var found bool
-	for _, item := range act.Items {
-		if item.Title == "Mobile Development Planning" {
-			found = true
-			// Date should be extracted from filename: 2026-01-15
-			if item.Timestamp.Day() != 15 {
-				t.Errorf("Timestamp day = %d, want 15", item.Timestamp.Day())
-			}
-		}
-	}
-
-	if !found {
-		t.Error("mobile planning session not found")
-	}
-}
-
-func TestAISource_ParsesLearnings(t *testing.T) {
-	aiDir := setupTestAIDir(t)
-
-	cfg := &config.AIConfig{
-		Enabled:          true,
-		Dir:              aiDir,
-		IncludeSessions:  false,
-		IncludeLearnings: true,
-		IncludeResearch:  false,
-	}
-
-	source := NewAISource(cfg)
-
-	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	if len(act.Items) != 1 {
-		t.Fatalf("expected 1 learning item, got %d", len(act.Items))
-	}
-
-	item := act.Items[0]
-	if item.Type != "learning" {
-		t.Errorf("Type = %q, want %q", item.Type, "learning")
-	}
-	if item.Timestamp.Day() != 18 {
-		t.Errorf("Timestamp day = %d, want 18", item.Timestamp.Day())
-	}
-}
-
-func TestAISource_ParsesResearchOrgMode(t *testing.T) {
-	aiDir := setupTestAIDir(t)
-
-	cfg := &config.AIConfig{
-		Enabled:          true,
-		Dir:              aiDir,
-		IncludeSessions:  false,
-		IncludeLearnings: false,
-		IncludeResearch:  true,
-	}
-
-	source := NewAISource(cfg)
-
-	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	if len(act.Items) != 1 {
-		t.Fatalf("expected 1 research item, got %d", len(act.Items))
-	}
-
-	item := act.Items[0]
-	if item.Type != "research" {
-		t.Errorf("Type = %q, want %q", item.Type, "research")
-	}
-	if item.Title != "SelfCI Analysis" {
-		t.Errorf("Title = %q, want %q", item.Title, "SelfCI Analysis")
-	}
-}
-
-func TestAISource_FiltersOutsideDateRange(t *testing.T) {
-	aiDir := setupTestAIDir(t)
-
-	cfg := &config.AIConfig{
-		Enabled:          true,
-		Dir:              aiDir,
-		IncludeSessions:  true,
-		IncludeLearnings: true,
-		IncludeResearch:  true,
-	}
-
-	source := NewAISource(cfg)
-
-	// Query for December 2025 - should return nothing
-	start := time.Date(2025, 12, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2025, 12, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	if len(act.Items) != 0 {
-		t.Errorf("expected 0 items outside date range, got %d", len(act.Items))
-	}
-}
-
-func TestAISource_Plans(t *testing.T) {
-	dir := t.TempDir()
-
-	// Plans are flat (no YYYY-MM subdirectories)
-	plansDir := filepath.Join(dir, "plans")
-	if err := os.MkdirAll(plansDir, 0o755); err != nil {
-		t.Fatalf("failed to create dir: %v", err)
-	}
-
-	content := `# Migration Plan
-
-**Date:** 2026-01-22
-
-## Overview
-Plan for migrating services.
-`
-	if err := os.WriteFile(filepath.Join(plansDir, "migration-plan.md"), []byte(content), 0o644); err != nil {
-		t.Fatalf("failed to write file: %v", err)
-	}
-
-	cfg := &config.AIConfig{
-		Enabled:      true,
-		Dir:          dir,
-		IncludePlans: true,
-	}
-
-	source := NewAISource(cfg)
-
-	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	if len(act.Items) != 1 {
-		t.Fatalf("expected 1 plan item, got %d", len(act.Items))
-	}
-
-	item := act.Items[0]
-	if item.Type != "plan" {
-		t.Errorf("Type = %q, want %q", item.Type, "plan")
-	}
-	if item.Title != "Migration Plan" {
-		t.Errorf("Title = %q, want %q", item.Title, "Migration Plan")
-	}
-}
-
-func TestAISource_ExtractsMetadata(t *testing.T) {
-	dir := t.TempDir()
-	sessionsDir := filepath.Join(dir, "sessions", "2026-01")
-	if err := os.MkdirAll(sessionsDir, 0o755); err != nil {
-		t.Fatal(err)
-	}
-
-	content := `# Fix Pipeline Release
-
-**Date:** 2026-01-21
-**Project:** tektoncd/pipeline
-**Repository:** tektoncd/pipeline
-**Directory:** ~/src/tektoncd/pipeline
-**Tool:** pi
-**Host:** kyushu
-**Tags:** #tekton #ci
-
-## Summary
-Fixed release pipeline.
-`
-	if err := os.WriteFile(filepath.Join(sessionsDir, "2026-01-21-fix-pipeline.md"), []byte(content), 0o644); err != nil {
-		t.Fatal(err)
-	}
-
-	cfg := &config.AIConfig{
-		Enabled:         true,
-		Dir:             dir,
-		IncludeSessions: true,
-	}
-	source := NewAISource(cfg)
-
-	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if len(act.Items) != 1 {
-		t.Fatalf("expected 1 item, got %d", len(act.Items))
-	}
-
-	item := act.Items[0]
-	checks := map[string]string{
-		"project":    "tektoncd/pipeline",
-		"repository": "tektoncd/pipeline",
-		"directory":  "~/src/tektoncd/pipeline",
-		"tool":       "pi",
-		"host":       "kyushu",
-		"tags":       "#tekton #ci",
-	}
-	for key, want := range checks {
-		if got := item.Metadata[key]; got != want {
-			t.Errorf("Metadata[%q] = %q, want %q", key, got, want)
-		}
-	}
-}
-
-func TestAISource_ExtractsMetadataVariants(t *testing.T) {
-	dir := t.TempDir()
-	sessionsDir := filepath.Join(dir, "sessions", "2026-01")
-	if err := os.MkdirAll(sessionsDir, 0o755); err != nil {
-		t.Fatal(err)
-	}
-
-	// Test variant formats: **Key**: value (colon outside bold)
-	content := `# Session Title
-
-**Date**: 2026-01-20
-**Project**: tektoncd/plumbing
-**Working Directory**: /home/user/src/tektoncd/plumbing
-**Tool**: pi (Claude)
-
-## Summary
-Did some work.
-`
-	if err := os.WriteFile(filepath.Join(sessionsDir, "2026-01-20-variant.md"), []byte(content), 0o644); err != nil {
-		t.Fatal(err)
-	}
-
-	cfg := &config.AIConfig{
-		Enabled:         true,
-		Dir:             dir,
-		IncludeSessions: true,
-	}
-	source := NewAISource(cfg)
-
-	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if len(act.Items) != 1 {
-		t.Fatalf("expected 1 item, got %d", len(act.Items))
-	}
-
-	item := act.Items[0]
-	if item.Metadata["project"] != "tektoncd/plumbing" {
-		t.Errorf("project = %q, want %q", item.Metadata["project"], "tektoncd/plumbing")
-	}
-	if item.Metadata["directory"] != "/home/user/src/tektoncd/plumbing" {
-		t.Errorf("directory = %q, want %q", item.Metadata["directory"], "/home/user/src/tektoncd/plumbing")
-	}
-	if item.Metadata["tool"] != "pi (Claude)" {
-		t.Errorf("tool = %q, want %q", item.Metadata["tool"], "pi (Claude)")
-	}
-	if item.Timestamp.Day() != 20 {
-		t.Errorf("day = %d, want 20", item.Timestamp.Day())
-	}
-}
-
-func TestAISource_ValidateMissingDir(t *testing.T) {
-	cfg := &config.AIConfig{
-		Enabled: true,
-		Dir:     "/nonexistent/dir/that/doesnt/exist",
-	}
-
-	source := NewAISource(cfg)
-
-	if err := source.Validate(); err == nil {
-		t.Error("expected error for missing directory")
-	}
-}
tools/review-tool/internal/sources/github.go
@@ -1,558 +0,0 @@
-package sources
-
-import (
-	"bytes"
-	"context"
-	"encoding/json"
-	"fmt"
-	"os/exec"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-// GitHubSource fetches activity from GitHub via the gh CLI.
-type GitHubSource struct {
-	cfg *config.GitHubConfig
-}
-
-// NewGitHubSource creates a new GitHub source.
-func NewGitHubSource(cfg *config.GitHubConfig) *GitHubSource {
-	return &GitHubSource{cfg: cfg}
-}
-
-// Name returns the source identifier.
-func (g *GitHubSource) Name() string {
-	return "github"
-}
-
-// Validate checks if gh CLI is available and authenticated.
-func (g *GitHubSource) Validate() error {
-	cmd := exec.Command("gh", "auth", "status")
-	if err := cmd.Run(); err != nil {
-		return fmt.Errorf("gh CLI not authenticated: %w", err)
-	}
-	return nil
-}
-
-// Fetch retrieves GitHub activities within the time range.
-func (g *GitHubSource) Fetch(ctx context.Context, start, end time.Time) (*activity.Activity, error) {
-	act := &activity.Activity{
-		Source: "github",
-		Items:  []activity.ActivityItem{},
-	}
-
-	dateFilter := fmt.Sprintf(">%s", start.Format("2006-01-02"))
-
-	// Fetch merged PRs
-	if g.cfg.IncludePRs {
-		items, err := g.fetchPRs(ctx, dateFilter, "pr_merged", "--merged")
-		if err == nil {
-			act.Items = append(act.Items, filterByDateRange(items, start, end)...)
-		}
-	}
-
-	// Fetch reviewed PRs
-	if g.cfg.IncludeReviews {
-		items, err := g.fetchReviewedPRs(ctx, dateFilter)
-		if err == nil {
-			act.Items = append(act.Items, filterByDateRange(items, start, end)...)
-		}
-	}
-
-	// Fetch issues
-	if g.cfg.IncludeIssues {
-		items, err := g.fetchIssues(ctx, dateFilter)
-		if err == nil {
-			act.Items = append(act.Items, filterByDateRange(items, start, end)...)
-		}
-	}
-
-	// Fetch discussions
-	if g.cfg.IncludeDiscussions {
-		items, err := g.fetchDiscussions(ctx, start)
-		if err == nil {
-			act.Items = append(act.Items, filterByDateRange(items, start, end)...)
-		}
-	}
-
-	// Fetch comments
-	if g.cfg.IncludeComments {
-		items, err := g.fetchComments(ctx, start)
-		if err == nil {
-			act.Items = append(act.Items, filterByDateRange(items, start, end)...)
-		}
-	}
-
-	return act, nil
-}
-
-func (g *GitHubSource) fetchPRs(ctx context.Context, dateFilter, itemType, extraFlag string) ([]activity.ActivityItem, error) {
-	args := []string{
-		"search", "prs",
-		"--author=@me",
-		fmt.Sprintf("--merged-at=%s", dateFilter),
-		"--json", "number,title,url,repository,closedAt",
-		"--limit", "100",
-	}
-	if extraFlag != "" && extraFlag != "--merged" {
-		args = append(args, extraFlag)
-	}
-
-	cmd := exec.CommandContext(ctx, "gh", args...)
-	var stdout, stderr bytes.Buffer
-	cmd.Stdout = &stdout
-	cmd.Stderr = &stderr
-
-	if err := cmd.Run(); err != nil {
-		return nil, fmt.Errorf("gh search prs failed: %s", stderr.String())
-	}
-
-	return parsePRJSON(stdout.Bytes(), itemType)
-}
-
-func (g *GitHubSource) fetchReviewedPRs(ctx context.Context, dateFilter string) ([]activity.ActivityItem, error) {
-	args := []string{
-		"search", "prs",
-		"--reviewed-by=@me",
-		fmt.Sprintf("--updated=%s", dateFilter),
-		"--json", "number,title,url,repository,closedAt",
-		"--limit", "100",
-	}
-
-	cmd := exec.CommandContext(ctx, "gh", args...)
-	var stdout, stderr bytes.Buffer
-	cmd.Stdout = &stdout
-	cmd.Stderr = &stderr
-
-	if err := cmd.Run(); err != nil {
-		return nil, fmt.Errorf("gh search prs (reviewed) failed: %s", stderr.String())
-	}
-
-	return parsePRJSON(stdout.Bytes(), "pr_reviewed")
-}
-
-func (g *GitHubSource) fetchIssues(ctx context.Context, dateFilter string) ([]activity.ActivityItem, error) {
-	args := []string{
-		"search", "issues",
-		"--author=@me",
-		fmt.Sprintf("--created=%s", dateFilter),
-		"--json", "number,title,url,repository,createdAt",
-		"--limit", "100",
-	}
-
-	cmd := exec.CommandContext(ctx, "gh", args...)
-	var stdout, stderr bytes.Buffer
-	cmd.Stdout = &stdout
-	cmd.Stderr = &stderr
-
-	if err := cmd.Run(); err != nil {
-		return nil, fmt.Errorf("gh search issues failed: %s", stderr.String())
-	}
-
-	return parseIssueJSON(stdout.Bytes())
-}
-
-// prResult represents a PR from gh search
-type prResult struct {
-	Number     int    `json:"number"`
-	Title      string `json:"title"`
-	URL        string `json:"url"`
-	ClosedAt   string `json:"closedAt"`
-	Repository struct {
-		Name          string `json:"name"`
-		NameWithOwner string `json:"nameWithOwner"`
-	} `json:"repository"`
-}
-
-// issueResult represents an issue from gh search
-type issueResult struct {
-	Number     int    `json:"number"`
-	Title      string `json:"title"`
-	URL        string `json:"url"`
-	CreatedAt  string `json:"createdAt"`
-	Repository struct {
-		Name          string `json:"name"`
-		NameWithOwner string `json:"nameWithOwner"`
-	} `json:"repository"`
-}
-
-func parsePRJSON(data []byte, itemType string) ([]activity.ActivityItem, error) {
-	var prs []prResult
-	if err := json.Unmarshal(data, &prs); err != nil {
-		return nil, err
-	}
-
-	items := make([]activity.ActivityItem, 0, len(prs))
-	for _, pr := range prs {
-		ts, _ := time.Parse(time.RFC3339, pr.ClosedAt)
-
-		items = append(items, activity.ActivityItem{
-			ID:        fmt.Sprintf("github:pr:%s:%d", pr.Repository.NameWithOwner, pr.Number),
-			Title:     pr.Title,
-			Type:      itemType,
-			Category:  activity.CategoryGitHub,
-			Timestamp: ts,
-			URL:       pr.URL,
-			Metadata: map[string]string{
-				"repository": pr.Repository.NameWithOwner,
-				"number":     fmt.Sprintf("%d", pr.Number),
-			},
-		})
-	}
-
-	return items, nil
-}
-
-func parseIssueJSON(data []byte) ([]activity.ActivityItem, error) {
-	var issues []issueResult
-	if err := json.Unmarshal(data, &issues); err != nil {
-		return nil, err
-	}
-
-	items := make([]activity.ActivityItem, 0, len(issues))
-	for _, issue := range issues {
-		ts, _ := time.Parse(time.RFC3339, issue.CreatedAt)
-
-		items = append(items, activity.ActivityItem{
-			ID:        fmt.Sprintf("github:issue:%s:%d", issue.Repository.NameWithOwner, issue.Number),
-			Title:     issue.Title,
-			Type:      "issue_created",
-			Category:  activity.CategoryGitHub,
-			Timestamp: ts,
-			URL:       issue.URL,
-			Metadata: map[string]string{
-				"repository": issue.Repository.NameWithOwner,
-				"number":     fmt.Sprintf("%d", issue.Number),
-			},
-		})
-	}
-
-	return items, nil
-}
-
-func (g *GitHubSource) fetchDiscussions(ctx context.Context, since time.Time) ([]activity.ActivityItem, error) {
-	// Use GraphQL to search for discussions authored by the user
-	query := `{
-  viewer {
-    repositoryDiscussions(first: 50, orderBy: {field: CREATED_AT, direction: DESC}) {
-      nodes {
-        title
-        url
-        createdAt
-        category {
-          name
-        }
-        repository {
-          nameWithOwner
-        }
-      }
-    }
-    repositoryDiscussionComments(first: 50) {
-      nodes {
-        discussion {
-          title
-          url
-          repository {
-            nameWithOwner
-          }
-        }
-        createdAt
-        url
-      }
-    }
-  }
-}`
-	args := []string{
-		"api", "graphql",
-		"-f", fmt.Sprintf("query=%s", query),
-	}
-
-	cmd := exec.CommandContext(ctx, "gh", args...)
-	var stdout, stderr bytes.Buffer
-	cmd.Stdout = &stdout
-	cmd.Stderr = &stderr
-
-	if err := cmd.Run(); err != nil {
-		return nil, fmt.Errorf("gh api graphql failed: %s", stderr.String())
-	}
-
-	return parseDiscussionGraphQL(stdout.Bytes(), since)
-}
-
-// graphqlDiscussionResponse represents the GraphQL response
-type graphqlDiscussionResponse struct {
-	Data struct {
-		Viewer struct {
-			RepositoryDiscussions struct {
-				Nodes []struct {
-					Title     string `json:"title"`
-					URL       string `json:"url"`
-					CreatedAt string `json:"createdAt"`
-					Category  struct {
-						Name string `json:"name"`
-					} `json:"category"`
-					Repository struct {
-						NameWithOwner string `json:"nameWithOwner"`
-					} `json:"repository"`
-				} `json:"nodes"`
-			} `json:"repositoryDiscussions"`
-			RepositoryDiscussionComments struct {
-				Nodes []struct {
-					Discussion struct {
-						Title      string `json:"title"`
-						URL        string `json:"url"`
-						Repository struct {
-							NameWithOwner string `json:"nameWithOwner"`
-						} `json:"repository"`
-					} `json:"discussion"`
-					CreatedAt string `json:"createdAt"`
-					URL       string `json:"url"`
-				} `json:"nodes"`
-			} `json:"repositoryDiscussionComments"`
-		} `json:"viewer"`
-	} `json:"data"`
-}
-
-func parseDiscussionGraphQL(data []byte, since time.Time) ([]activity.ActivityItem, error) {
-	var resp graphqlDiscussionResponse
-	if err := json.Unmarshal(data, &resp); err != nil {
-		return nil, err
-	}
-
-	var items []activity.ActivityItem
-	seen := make(map[string]bool)
-
-	// Add discussions authored by user
-	for _, d := range resp.Data.Viewer.RepositoryDiscussions.Nodes {
-		ts, _ := time.Parse(time.RFC3339, d.CreatedAt)
-		if ts.Before(since) {
-			continue
-		}
-		if seen[d.URL] {
-			continue
-		}
-		seen[d.URL] = true
-
-		items = append(items, activity.ActivityItem{
-			ID:        fmt.Sprintf("github:discussion:%s", d.URL),
-			Title:     d.Title,
-			Type:      "discussion",
-			Category:  activity.CategoryGitHub,
-			Timestamp: ts,
-			URL:       d.URL,
-			Metadata: map[string]string{
-				"repository": d.Repository.NameWithOwner,
-				"category":   d.Category.Name,
-			},
-		})
-	}
-
-	// Add discussions where user commented
-	for _, c := range resp.Data.Viewer.RepositoryDiscussionComments.Nodes {
-		ts, _ := time.Parse(time.RFC3339, c.CreatedAt)
-		if ts.Before(since) {
-			continue
-		}
-		if seen[c.URL] {
-			continue
-		}
-		seen[c.URL] = true
-
-		items = append(items, activity.ActivityItem{
-			ID:        fmt.Sprintf("github:discussion_comment:%s", c.URL),
-			Title:     fmt.Sprintf("Comment on discussion: %s", c.Discussion.Title),
-			Type:      "discussion_comment",
-			Category:  activity.CategoryGitHub,
-			Timestamp: ts,
-			URL:       c.URL,
-			Metadata: map[string]string{
-				"repository":       c.Discussion.Repository.NameWithOwner,
-				"discussion_title": c.Discussion.Title,
-			},
-		})
-	}
-
-	return items, nil
-}
-
-func (g *GitHubSource) fetchComments(ctx context.Context, since time.Time) ([]activity.ActivityItem, error) {
-	// Use GraphQL to get issue/PR comments by the user
-	query := `{
-  viewer {
-    issueComments(first: 50, orderBy: {field: UPDATED_AT, direction: DESC}) {
-      nodes {
-        body
-        url
-        createdAt
-        issue {
-          title
-          number
-          repository {
-            nameWithOwner
-          }
-        }
-      }
-    }
-  }
-}`
-	args := []string{
-		"api", "graphql",
-		"-f", fmt.Sprintf("query=%s", query),
-	}
-
-	cmd := exec.CommandContext(ctx, "gh", args...)
-	var stdout, stderr bytes.Buffer
-	cmd.Stdout = &stdout
-	cmd.Stderr = &stderr
-
-	if err := cmd.Run(); err != nil {
-		return nil, fmt.Errorf("gh api graphql (comments) failed: %s", stderr.String())
-	}
-
-	return parseCommentsGraphQL(stdout.Bytes(), since)
-}
-
-// graphqlCommentsResponse represents the GraphQL response for comments
-type graphqlCommentsResponse struct {
-	Data struct {
-		Viewer struct {
-			IssueComments struct {
-				Nodes []struct {
-					Body      string `json:"body"`
-					URL       string `json:"url"`
-					CreatedAt string `json:"createdAt"`
-					Issue     struct {
-						Title      string `json:"title"`
-						Number     int    `json:"number"`
-						Repository struct {
-							NameWithOwner string `json:"nameWithOwner"`
-						} `json:"repository"`
-					} `json:"issue"`
-				} `json:"nodes"`
-			} `json:"issueComments"`
-		} `json:"viewer"`
-	} `json:"data"`
-}
-
-func parseCommentsGraphQL(data []byte, since time.Time) ([]activity.ActivityItem, error) {
-	var resp graphqlCommentsResponse
-	if err := json.Unmarshal(data, &resp); err != nil {
-		return nil, err
-	}
-
-	var items []activity.ActivityItem
-	seen := make(map[string]bool)
-
-	for _, c := range resp.Data.Viewer.IssueComments.Nodes {
-		ts, _ := time.Parse(time.RFC3339, c.CreatedAt)
-		if ts.Before(since) {
-			continue
-		}
-		if seen[c.URL] {
-			continue
-		}
-		seen[c.URL] = true
-
-		items = append(items, activity.ActivityItem{
-			ID:        fmt.Sprintf("github:comment:%s", c.URL),
-			Title:     fmt.Sprintf("Comment on: %s", c.Issue.Title),
-			Type:      "comment",
-			Category:  activity.CategoryGitHub,
-			Timestamp: ts,
-			URL:       c.URL,
-			Metadata: map[string]string{
-				"repository":   c.Issue.Repository.NameWithOwner,
-				"issue_number": fmt.Sprintf("%d", c.Issue.Number),
-				"issue_title":  c.Issue.Title,
-			},
-		})
-	}
-
-	return items, nil
-}
-
-func filterByDateRange(items []activity.ActivityItem, start, end time.Time) []activity.ActivityItem {
-	filtered := make([]activity.ActivityItem, 0)
-	for _, item := range items {
-		if !item.Timestamp.Before(start) && !item.Timestamp.After(end) {
-			filtered = append(filtered, item)
-		}
-	}
-	return filtered
-}
-
-// discussionResult represents a discussion from GraphQL API
-type discussionResult struct {
-	Title      string `json:"title"`
-	URL        string `json:"url"`
-	CreatedAt  string `json:"createdAt"`
-	Repository string `json:"repository"`
-	Category   string `json:"category"`
-}
-
-// commentResult represents a comment from GraphQL API
-type commentResult struct {
-	Body        string `json:"body"`
-	URL         string `json:"url"`
-	CreatedAt   string `json:"createdAt"`
-	Repository  string `json:"repository"`
-	IssueTitle  string `json:"issueTitle"`
-	IssueNumber int    `json:"issueNumber"`
-}
-
-func parseDiscussionJSON(data []byte) ([]activity.ActivityItem, error) {
-	var discussions []discussionResult
-	if err := json.Unmarshal(data, &discussions); err != nil {
-		return nil, err
-	}
-
-	items := make([]activity.ActivityItem, 0, len(discussions))
-	for _, d := range discussions {
-		ts, _ := time.Parse(time.RFC3339, d.CreatedAt)
-
-		items = append(items, activity.ActivityItem{
-			ID:        fmt.Sprintf("github:discussion:%s", d.URL),
-			Title:     d.Title,
-			Type:      "discussion",
-			Category:  activity.CategoryGitHub,
-			Timestamp: ts,
-			URL:       d.URL,
-			Metadata: map[string]string{
-				"repository": d.Repository,
-				"category":   d.Category,
-			},
-		})
-	}
-
-	return items, nil
-}
-
-func parseCommentJSON(data []byte) ([]activity.ActivityItem, error) {
-	var comments []commentResult
-	if err := json.Unmarshal(data, &comments); err != nil {
-		return nil, err
-	}
-
-	items := make([]activity.ActivityItem, 0, len(comments))
-	for _, c := range comments {
-		ts, _ := time.Parse(time.RFC3339, c.CreatedAt)
-
-		items = append(items, activity.ActivityItem{
-			ID:        fmt.Sprintf("github:comment:%s", c.URL),
-			Title:     fmt.Sprintf("Comment on: %s", c.IssueTitle),
-			Type:      "comment",
-			Category:  activity.CategoryGitHub,
-			Timestamp: ts,
-			URL:       c.URL,
-			Metadata: map[string]string{
-				"repository":   c.Repository,
-				"issue_number": fmt.Sprintf("%d", c.IssueNumber),
-				"issue_title":  c.IssueTitle,
-			},
-		})
-	}
-
-	return items, nil
-}
tools/review-tool/internal/sources/github_test.go
@@ -1,215 +0,0 @@
-package sources
-
-import (
-	"os/exec"
-	"testing"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-func TestGitHubSource_ParsePRJSON(t *testing.T) {
-	// Test JSON parsing logic directly
-	jsonData := `[{"closedAt":"2026-01-27T10:44:31Z","number":9305,"repository":{"name":"pipeline","nameWithOwner":"tektoncd/pipeline"},"title":"Fix CI workflow","url":"https://github.com/tektoncd/pipeline/pull/9305"}]`
-
-	items, err := parsePRJSON([]byte(jsonData), "pr_merged")
-	if err != nil {
-		t.Fatalf("parsePRJSON() error = %v", err)
-	}
-
-	if len(items) != 1 {
-		t.Fatalf("expected 1 item, got %d", len(items))
-	}
-
-	item := items[0]
-	if item.Title != "Fix CI workflow" {
-		t.Errorf("Title = %q, want %q", item.Title, "Fix CI workflow")
-	}
-	if item.Type != "pr_merged" {
-		t.Errorf("Type = %q, want %q", item.Type, "pr_merged")
-	}
-	if item.Category != activity.CategoryGitHub {
-		t.Errorf("Category = %q, want %q", item.Category, activity.CategoryGitHub)
-	}
-	if item.URL != "https://github.com/tektoncd/pipeline/pull/9305" {
-		t.Errorf("URL = %q, want correct URL", item.URL)
-	}
-	if item.Metadata["repository"] != "tektoncd/pipeline" {
-		t.Errorf("repository = %q, want %q", item.Metadata["repository"], "tektoncd/pipeline")
-	}
-}
-
-func TestGitHubSource_ParseMultiplePRs(t *testing.T) {
-	jsonData := `[
-		{"closedAt":"2026-01-27T10:00:00Z","number":1,"repository":{"nameWithOwner":"org/repo1"},"title":"PR 1","url":"https://github.com/org/repo1/pull/1"},
-		{"closedAt":"2026-01-26T09:00:00Z","number":2,"repository":{"nameWithOwner":"org/repo2"},"title":"PR 2","url":"https://github.com/org/repo2/pull/2"}
-	]`
-
-	items, err := parsePRJSON([]byte(jsonData), "pr_merged")
-	if err != nil {
-		t.Fatalf("parsePRJSON() error = %v", err)
-	}
-
-	if len(items) != 2 {
-		t.Fatalf("expected 2 items, got %d", len(items))
-	}
-}
-
-func TestGitHubSource_FilterByDateRange(t *testing.T) {
-	// Create items with different dates
-	items := []activity.ActivityItem{
-		{Title: "Old PR", Timestamp: time.Date(2026, 1, 10, 0, 0, 0, 0, time.UTC)},
-		{Title: "Recent PR", Timestamp: time.Date(2026, 1, 25, 0, 0, 0, 0, time.UTC)},
-		{Title: "Future PR", Timestamp: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC)},
-	}
-
-	start := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	filtered := filterByDateRange(items, start, end)
-
-	if len(filtered) != 1 {
-		t.Errorf("expected 1 item in range, got %d", len(filtered))
-	}
-	if len(filtered) > 0 && filtered[0].Title != "Recent PR" {
-		t.Errorf("expected 'Recent PR', got %q", filtered[0].Title)
-	}
-}
-
-func TestGitHubSource_ParseDiscussionJSON(t *testing.T) {
-	jsonData := `[
-		{
-			"title": "How to configure CI/CD?",
-			"url": "https://github.com/tektoncd/pipeline/discussions/123",
-			"createdAt": "2026-01-25T14:30:00Z",
-			"repository": "tektoncd/pipeline",
-			"category": "Q&A"
-		}
-	]`
-
-	items, err := parseDiscussionJSON([]byte(jsonData))
-	if err != nil {
-		t.Fatalf("parseDiscussionJSON() error = %v", err)
-	}
-
-	if len(items) != 1 {
-		t.Fatalf("expected 1 item, got %d", len(items))
-	}
-
-	item := items[0]
-	if item.Title != "How to configure CI/CD?" {
-		t.Errorf("Title = %q, want %q", item.Title, "How to configure CI/CD?")
-	}
-	if item.Type != "discussion" {
-		t.Errorf("Type = %q, want %q", item.Type, "discussion")
-	}
-	if item.Category != activity.CategoryGitHub {
-		t.Errorf("Category = %q, want %q", item.Category, activity.CategoryGitHub)
-	}
-	if item.Metadata["category"] != "Q&A" {
-		t.Errorf("category = %q, want %q", item.Metadata["category"], "Q&A")
-	}
-}
-
-func TestGitHubSource_ParseCommentJSON(t *testing.T) {
-	jsonData := `[
-		{
-			"body": "Thanks for the fix!",
-			"url": "https://github.com/tektoncd/pipeline/issues/456#issuecomment-123",
-			"createdAt": "2026-01-26T10:15:00Z",
-			"repository": "tektoncd/pipeline",
-			"issueTitle": "Bug in pipeline controller",
-			"issueNumber": 456
-		}
-	]`
-
-	items, err := parseCommentJSON([]byte(jsonData))
-	if err != nil {
-		t.Fatalf("parseCommentJSON() error = %v", err)
-	}
-
-	if len(items) != 1 {
-		t.Fatalf("expected 1 item, got %d", len(items))
-	}
-
-	item := items[0]
-	if item.Title != "Comment on: Bug in pipeline controller" {
-		t.Errorf("Title = %q, want %q", item.Title, "Comment on: Bug in pipeline controller")
-	}
-	if item.Type != "comment" {
-		t.Errorf("Type = %q, want %q", item.Type, "comment")
-	}
-	if item.Metadata["issue_number"] != "456" {
-		t.Errorf("issue_number = %q, want %q", item.Metadata["issue_number"], "456")
-	}
-}
-
-// Integration test - requires gh CLI
-func TestGitHubSource_RealData(t *testing.T) {
-	// Check if gh CLI is available
-	if _, err := exec.LookPath("gh"); err != nil {
-		t.Skip("gh CLI not found, skipping integration test")
-	}
-
-	cfg := &config.GitHubConfig{
-		Enabled:        true,
-		IncludePRs:     true,
-		IncludeIssues:  false,
-		IncludeReviews: false,
-		IncludeCommits: false,
-	}
-
-	source := NewGitHubSource(cfg)
-
-	// Last 7 days
-	now := time.Now()
-	start := time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, now.Location())
-
-	act, err := source.Fetch(t.Context(), start, now)
-	if err != nil {
-		t.Fatalf("Fetch error: %v", err)
-	}
-
-	t.Logf("Found %d GitHub items", len(act.Items))
-	for i, item := range act.Items {
-		if i < 5 {
-			t.Logf("  [%s] %s (%s)", item.Type, item.Title, item.Metadata["repository"])
-		}
-	}
-}
-
-// Integration test for discussions and comments
-func TestGitHubSource_DiscussionsAndComments(t *testing.T) {
-	if _, err := exec.LookPath("gh"); err != nil {
-		t.Skip("gh CLI not found, skipping integration test")
-	}
-
-	cfg := &config.GitHubConfig{
-		Enabled:            true,
-		IncludePRs:         false,
-		IncludeIssues:      false,
-		IncludeReviews:     false,
-		IncludeCommits:     false,
-		IncludeDiscussions: true,
-		IncludeComments:    true,
-	}
-
-	source := NewGitHubSource(cfg)
-
-	// Last 7 days
-	now := time.Now()
-	start := time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, now.Location())
-
-	act, err := source.Fetch(t.Context(), start, now)
-	if err != nil {
-		t.Fatalf("Fetch error: %v", err)
-	}
-
-	t.Logf("Found %d discussion/comment items", len(act.Items))
-	for i, item := range act.Items {
-		if i < 10 {
-			t.Logf("  [%s] %s (%s)", item.Type, item.Title, item.Metadata["repository"])
-		}
-	}
-}
tools/review-tool/internal/sources/jira.go
@@ -1,141 +0,0 @@
-package sources
-
-import (
-	"bytes"
-	"context"
-	"fmt"
-	"os/exec"
-	"regexp"
-	"strings"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-// JiraSource fetches activity from Jira via the jira CLI.
-type JiraSource struct {
-	cfg *config.JiraConfig
-}
-
-// NewJiraSource creates a new Jira source.
-func NewJiraSource(cfg *config.JiraConfig) *JiraSource {
-	return &JiraSource{cfg: cfg}
-}
-
-// Name returns the source identifier.
-func (j *JiraSource) Name() string {
-	return "jira"
-}
-
-// Validate checks if jira CLI is available and configured.
-func (j *JiraSource) Validate() error {
-	cmd := exec.Command("jira", "me")
-	if err := cmd.Run(); err != nil {
-		return fmt.Errorf("jira CLI not configured: %w", err)
-	}
-	return nil
-}
-
-// Fetch retrieves Jira activities within the time range.
-func (j *JiraSource) Fetch(ctx context.Context, start, end time.Time) (*activity.Activity, error) {
-	act := &activity.Activity{
-		Source: "jira",
-		Items:  []activity.ActivityItem{},
-	}
-
-	// Calculate days since start
-	daysSince := int(time.Since(start).Hours()/24) + 1
-
-	// Build JQL query
-	var jql string
-	if len(j.cfg.Projects) > 0 {
-		projects := strings.Join(j.cfg.Projects, ", ")
-		jql = fmt.Sprintf("project in (%s) AND assignee = currentUser() AND updated >= -%dd", projects, daysSince)
-	} else {
-		jql = fmt.Sprintf("assignee = currentUser() AND updated >= -%dd", daysSince)
-	}
-
-	// Execute jira CLI
-	args := []string{
-		"issue", "list",
-		"--jql", jql,
-		"--plain",
-		"--columns", "key,summary,status,updated",
-	}
-
-	cmd := exec.CommandContext(ctx, "jira", args...)
-	var stdout, stderr bytes.Buffer
-	cmd.Stdout = &stdout
-	cmd.Stderr = &stderr
-
-	if err := cmd.Run(); err != nil {
-		return act, nil // Return empty activity on error, don't fail
-	}
-
-	items, err := parseJiraPlainOutput(stdout.String(), j.cfg.Server)
-	if err != nil {
-		return act, nil
-	}
-
-	act.Items = filterByDateRange(items, start, end)
-	return act, nil
-}
-
-// parseJiraPlainOutput parses the --plain output from jira CLI
-func parseJiraPlainOutput(output, serverURL string) ([]activity.ActivityItem, error) {
-	lines := strings.Split(output, "\n")
-	if len(lines) < 2 {
-		return nil, nil // No data
-	}
-
-	// Skip header line
-	var items []activity.ActivityItem
-
-	// Parse each line (tab-separated)
-	// Format: KEY\tSUMMARY\tSTATUS\tUPDATED
-	tabRe := regexp.MustCompile(`\t+`)
-
-	for _, line := range lines[1:] {
-		line = strings.TrimSpace(line)
-		if line == "" {
-			continue
-		}
-
-		fields := tabRe.Split(line, -1)
-		if len(fields) < 4 {
-			continue
-		}
-
-		key := strings.TrimSpace(fields[0])
-		summary := strings.TrimSpace(fields[1])
-		status := strings.TrimSpace(fields[2])
-		updated := strings.TrimSpace(fields[3])
-
-		ts, err := parseJiraTimestamp(updated)
-		if err != nil {
-			continue
-		}
-
-		items = append(items, activity.ActivityItem{
-			ID:        fmt.Sprintf("jira:%s", key),
-			Title:     summary,
-			Type:      "issue_updated",
-			Category:  activity.CategoryJira,
-			Timestamp: ts,
-			URL:       fmt.Sprintf("%s/browse/%s", serverURL, key),
-			Metadata: map[string]string{
-				"key":    key,
-				"status": status,
-			},
-		})
-	}
-
-	return items, nil
-}
-
-// parseJiraTimestamp parses Jira's timestamp format
-func parseJiraTimestamp(s string) (time.Time, error) {
-	// Format: 2026-01-26 15:55:24
-	return time.Parse("2006-01-02 15:04:05", s)
-}
tools/review-tool/internal/sources/jira_test.go
@@ -1,109 +0,0 @@
-package sources
-
-import (
-	"os/exec"
-	"testing"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-func TestJiraSource_ParsePlainOutput(t *testing.T) {
-	// Test parsing jira CLI plain output
-	plainOutput := `KEY		SUMMARY											STATUS	UPDATED
-SRVKP-9988	Fix performance issue								On QA	2026-01-26 15:55:24
-SRVKP-1234	Implement new feature								Done	2026-01-25 10:00:00`
-
-	items, err := parseJiraPlainOutput(plainOutput, "https://issues.redhat.com")
-	if err != nil {
-		t.Fatalf("parseJiraPlainOutput() error = %v", err)
-	}
-
-	if len(items) != 2 {
-		t.Fatalf("expected 2 items, got %d", len(items))
-	}
-
-	// Check first item
-	item := items[0]
-	if item.Title != "Fix performance issue" {
-		t.Errorf("Title = %q, want %q", item.Title, "Fix performance issue")
-	}
-	if item.Type != "issue_updated" {
-		t.Errorf("Type = %q, want %q", item.Type, "issue_updated")
-	}
-	if item.Category != activity.CategoryJira {
-		t.Errorf("Category = %q, want %q", item.Category, activity.CategoryJira)
-	}
-	if item.Metadata["key"] != "SRVKP-9988" {
-		t.Errorf("key = %q, want %q", item.Metadata["key"], "SRVKP-9988")
-	}
-	if item.Metadata["status"] != "On QA" {
-		t.Errorf("status = %q, want %q", item.Metadata["status"], "On QA")
-	}
-	if item.URL != "https://issues.redhat.com/browse/SRVKP-9988" {
-		t.Errorf("URL = %q, want correct URL", item.URL)
-	}
-}
-
-func TestJiraSource_ParseTimestamp(t *testing.T) {
-	ts, err := parseJiraTimestamp("2026-01-26 15:55:24")
-	if err != nil {
-		t.Fatalf("parseJiraTimestamp() error = %v", err)
-	}
-
-	if ts.Day() != 26 || ts.Month() != 1 || ts.Year() != 2026 {
-		t.Errorf("parsed date wrong: %v", ts)
-	}
-	if ts.Hour() != 15 || ts.Minute() != 55 {
-		t.Errorf("parsed time wrong: %v", ts)
-	}
-}
-
-func TestJiraSource_FilterByDateRange(t *testing.T) {
-	items := []activity.ActivityItem{
-		{Title: "Old issue", Timestamp: time.Date(2026, 1, 10, 0, 0, 0, 0, time.UTC)},
-		{Title: "Recent issue", Timestamp: time.Date(2026, 1, 25, 0, 0, 0, 0, time.UTC)},
-	}
-
-	start := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	filtered := filterByDateRange(items, start, end)
-
-	if len(filtered) != 1 {
-		t.Errorf("expected 1 item in range, got %d", len(filtered))
-	}
-}
-
-// Integration test - requires jira CLI
-func TestJiraSource_RealData(t *testing.T) {
-	// Check if jira CLI is available
-	if _, err := exec.LookPath("jira"); err != nil {
-		t.Skip("jira CLI not found, skipping integration test")
-	}
-
-	cfg := &config.JiraConfig{
-		Enabled:  true,
-		Server:   "https://issues.redhat.com",
-		Projects: []string{"SRVKP"},
-	}
-
-	source := NewJiraSource(cfg)
-
-	// Last 7 days
-	now := time.Now()
-	start := time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, now.Location())
-
-	act, err := source.Fetch(t.Context(), start, now)
-	if err != nil {
-		t.Fatalf("Fetch error: %v", err)
-	}
-
-	t.Logf("Found %d Jira items", len(act.Items))
-	for i, item := range act.Items {
-		if i < 5 {
-			t.Logf("  [%s] %s (%s)", item.Metadata["key"], item.Title, item.Metadata["status"])
-		}
-	}
-}
tools/review-tool/internal/sources/org.go
@@ -1,331 +0,0 @@
-package sources
-
-import (
-	"bufio"
-	"context"
-	"os"
-	"path/filepath"
-	"regexp"
-	"strings"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-var (
-	// ** DONE [#2] Some task title
-	orgHeadingRe = regexp.MustCompile(`^(\*+)\s+(TODO|DONE|STRT|NEXT|WAIT|CANX|CANCELED|KILL)\s+(?:\[#\d\]\s+)?(.+)$`)
-	// * Section heading (level 1, no TODO state)
-	sectionHeadingRe = regexp.MustCompile(`^\*\s+([^*].*)$`)
-	// - State "DONE"       from "TODO"       [2026-01-25 Sat 15:30]
-	stateChangeRe = regexp.MustCompile(`^-\s+State\s+"(\w+)"\s+from\s+"(\w+)"\s+\[(\d{4}-\d{2}-\d{2}\s+\w{3}\s+\d{2}:\d{2})\]`)
-	// CLOCK: [2026-01-22 Wed 09:00]--[2026-01-22 Wed 11:15] =>  2:15
-	clockEntryRe = regexp.MustCompile(`CLOCK:\s+\[([^\]]+)\]--\[([^\]]+)\]\s+=>\s+(\d+:\d+)`)
-	// Org-mode links: [[url][description]] or [[url]]
-	orgLinkWithDescRe = regexp.MustCompile(`\[\[([^\]]+)\]\[([^\]]+)\]\]`)
-	orgLinkBareRe     = regexp.MustCompile(`\[\[([^\]]+)\]\]`)
-	// Org-mode tags at end of heading: :tag1:tag2:
-	orgTagsRe = regexp.MustCompile(`\s+:[A-Za-z0-9_@#%:]+:\s*$`)
-)
-
-// OrgSource fetches activity from org-mode files.
-type OrgSource struct {
-	cfg *config.OrgConfig
-}
-
-// NewOrgSource creates a new org-mode source.
-func NewOrgSource(cfg *config.OrgConfig) *OrgSource {
-	return &OrgSource{cfg: cfg}
-}
-
-// Name returns the source identifier.
-func (o *OrgSource) Name() string {
-	return "org"
-}
-
-// Validate checks if org files are accessible.
-func (o *OrgSource) Validate() error {
-	for _, f := range o.cfg.Files {
-		if _, err := os.Stat(f); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// Fetch retrieves org-mode activities within the time range.
-func (o *OrgSource) Fetch(ctx context.Context, start, end time.Time) (*activity.Activity, error) {
-	act := &activity.Activity{
-		Source: "org",
-		Items:  []activity.ActivityItem{},
-	}
-
-	// Parse configured files
-	for _, filePath := range o.cfg.Files {
-		items, err := o.parseOrgFile(filePath, start, end)
-		if err != nil {
-			continue // Skip files that fail to parse
-		}
-		act.Items = append(act.Items, items...)
-	}
-
-	// Parse archive directory if configured
-	if o.cfg.ArchiveDir != "" {
-		items, err := o.parseArchiveDir(o.cfg.ArchiveDir, start, end)
-		if err == nil {
-			act.Items = append(act.Items, items...)
-		}
-	}
-
-	return act, nil
-}
-
-// parseArchiveDir scans an archive directory for org files with relevant state changes.
-// It processes .org files and extensionless files (common for org-mode archives).
-func (o *OrgSource) parseArchiveDir(dir string, start, end time.Time) ([]activity.ActivityItem, error) {
-	var items []activity.ActivityItem
-
-	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
-		if err != nil {
-			return nil // Skip errors
-		}
-
-		if info.IsDir() {
-			return nil
-		}
-
-		// Skip known non-org files
-		lower := strings.ToLower(path)
-		if shouldSkipArchiveFile(lower) {
-			return nil
-		}
-
-		fileItems, err := o.parseOrgFile(path, start, end)
-		if err != nil {
-			return nil
-		}
-
-		items = append(items, fileItems...)
-		return nil
-	})
-
-	return items, err
-}
-
-// shouldSkipArchiveFile returns true for files that are definitely not org-mode files.
-func shouldSkipArchiveFile(path string) bool {
-	// Skip backup and temp files
-	if strings.HasSuffix(path, "~") || strings.HasSuffix(path, ".bak") ||
-		strings.Contains(path, "#") || strings.HasSuffix(path, ".swp") {
-		return true
-	}
-
-	// Skip known binary/non-org extensions
-	skipExtensions := []string{
-		".html", ".htm", ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".svg",
-		".css", ".js", ".json", ".yaml", ".yml", ".xml",
-		".tar", ".gz", ".xz", ".zip", ".bz2",
-		".ttf", ".woff", ".woff2", ".eot",
-		".md", ".txt", ".log", ".ico", ".gpg",
-	}
-	for _, ext := range skipExtensions {
-		if strings.HasSuffix(path, ext) {
-			return true
-		}
-	}
-
-	// Skip legacy.bak directory
-	if strings.Contains(path, "legacy.bak") {
-		return true
-	}
-
-	return false
-}
-
-func (o *OrgSource) parseOrgFile(filePath string, start, end time.Time) ([]activity.ActivityItem, error) {
-	file, err := os.Open(filePath)
-	if err != nil {
-		return nil, err
-	}
-	defer file.Close()
-
-	var items []activity.ActivityItem
-	var currentHeading string
-	var currentSection string          // Reset for each file
-	seenItems := make(map[string]bool) // Dedup by heading+timestamp
-
-	scanner := bufio.NewScanner(file)
-	for scanner.Scan() {
-		line := scanner.Text()
-
-		// Track section (level-1 heading without TODO state)
-		// Must be exactly one asterisk followed by space (not ** or more)
-		if strings.HasPrefix(line, "* ") && !strings.HasPrefix(line, "** ") {
-			// Only update section if this is a plain heading (not a TODO)
-			if !orgHeadingRe.MatchString(line) {
-				// Extract section name and convert any org links
-				sectionName := strings.TrimPrefix(line, "* ")
-				sectionName = strings.TrimSpace(sectionName)
-				// Remove any tags at the end (like :ARCHIVE:)
-				if idx := strings.LastIndex(sectionName, ":"); idx > 0 {
-					// Check if this looks like a tag (ends with :)
-					if strings.HasSuffix(sectionName, ":") {
-						tagStart := strings.LastIndex(sectionName[:idx], " ")
-						if tagStart > 0 {
-							sectionName = strings.TrimSpace(sectionName[:tagStart])
-						}
-					}
-				}
-				currentSection = convertOrgLinksToMarkdown(sectionName)
-			}
-		}
-
-		// Track current heading context
-		if matches := orgHeadingRe.FindStringSubmatch(line); len(matches) > 0 {
-			currentHeading = strings.TrimSpace(matches[3])
-		}
-
-		// Parse state changes (DONE from TODO, etc.)
-		if o.cfg.IncludeDone || o.cfg.IncludeStateChanges {
-			if matches := stateChangeRe.FindStringSubmatch(line); len(matches) > 0 {
-				toState := matches[1]
-				// Only capture transitions to DONE
-				if toState == "DONE" && currentHeading != "" {
-					ts, err := parseOrgTimestamp(matches[3])
-					if err != nil {
-						continue
-					}
-
-					// Filter by date range
-					if ts.Before(start) || ts.After(end) {
-						continue
-					}
-
-					key := currentHeading + ts.Format("2006-01-02-15:04")
-					if seenItems[key] {
-						continue
-					}
-					seenItems[key] = true
-
-					title := cleanOrgTitle(currentHeading)
-					metadata := map[string]string{
-						"file":       filePath,
-						"from_state": matches[2],
-					}
-					if currentSection != "" {
-						metadata["section"] = currentSection
-					}
-
-					items = append(items, activity.ActivityItem{
-						ID:        filePath + ":" + currentHeading,
-						Title:     title,
-						Type:      "todo_done",
-						Category:  activity.CategoryOrg,
-						Timestamp: ts,
-						Metadata:  metadata,
-					})
-				}
-			}
-		}
-
-		// Parse CLOCK entries
-		if o.cfg.IncludeClockEntries {
-			if matches := clockEntryRe.FindStringSubmatch(line); len(matches) > 0 && currentHeading != "" {
-				// Parse start time
-				ts, err := parseOrgTimestamp(matches[1])
-				if err != nil {
-					continue
-				}
-
-				// Filter by date range
-				if ts.Before(start) || ts.After(end) {
-					continue
-				}
-
-				duration := matches[3]
-
-				key := "clock:" + currentHeading + ts.Format("2006-01-02-15:04")
-				if seenItems[key] {
-					continue
-				}
-				seenItems[key] = true
-
-				title := cleanOrgTitle(currentHeading)
-				metadata := map[string]string{
-					"file":     filePath,
-					"duration": duration,
-				}
-				if currentSection != "" {
-					metadata["section"] = currentSection
-				}
-
-				items = append(items, activity.ActivityItem{
-					ID:        filePath + ":clock:" + currentHeading,
-					Title:     title,
-					Type:      "clock_entry",
-					Category:  activity.CategoryOrg,
-					Timestamp: ts,
-					Metadata:  metadata,
-				})
-			}
-		}
-	}
-
-	return items, nil
-}
-
-func parseOrgTimestamp(s string) (time.Time, error) {
-	// Try various org timestamp formats
-	formats := []string{
-		"2006-01-02 Mon 15:04",
-		"2006-01-02 Mon",
-		"2006-01-02",
-	}
-
-	s = strings.TrimSpace(s)
-	for _, format := range formats {
-		if t, err := time.Parse(format, s); err == nil {
-			return t, nil
-		}
-	}
-
-	// Try with different day names
-	// Replace day name with Mon to normalize
-	s = regexp.MustCompile(`\s+(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+`).ReplaceAllString(s, " Mon ")
-	for _, format := range formats {
-		if t, err := time.Parse(format, s); err == nil {
-			return t, nil
-		}
-	}
-
-	return time.Time{}, nil
-}
-
-// convertOrgLinksToMarkdown converts org-mode links to markdown format.
-// [[url][description]] -> [description](url)
-// [[url]] -> [url](url)
-func convertOrgLinksToMarkdown(s string) string {
-	// First, replace links with descriptions: [[url][desc]] -> [desc](url)
-	s = orgLinkWithDescRe.ReplaceAllString(s, "[$2]($1)")
-
-	// Then, replace bare links: [[url]] -> [url](url)
-	s = orgLinkBareRe.ReplaceAllStringFunc(s, func(match string) string {
-		// Extract the URL from [[url]]
-		url := orgLinkBareRe.FindStringSubmatch(match)[1]
-		return "[" + url + "](" + url + ")"
-	})
-
-	return s
-}
-
-// cleanOrgTitle removes org-mode artifacts from a title.
-// - Converts org links to markdown
-// - Removes trailing tags like :ARCHIVE:, :CANX:, etc.
-func cleanOrgTitle(s string) string {
-	// Remove trailing tags
-	s = orgTagsRe.ReplaceAllString(s, "")
-	// Convert links
-	s = convertOrgLinksToMarkdown(s)
-	return strings.TrimSpace(s)
-}
tools/review-tool/internal/sources/org_test.go
@@ -1,496 +0,0 @@
-package sources
-
-import (
-	"os"
-	"path/filepath"
-	"testing"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-func setupTestOrgFile(t *testing.T) string {
-	t.Helper()
-	dir := t.TempDir()
-
-	content := `#+title: Test TODOs
-
-* Work
-** DONE [#2] Review PR for feature X
-CLOSED: [2026-01-25 Sat 15:30] SCHEDULED: <2026-01-25 Sat>
-:PROPERTIES:
-:CREATED:       [2026-01-20 Tue 10:00]
-:CATEGORY: work
-:END:
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-25 Sat 15:30]
-:END:
-
-Reviewed and merged the PR.
-
-** DONE Fix critical bug in authentication
-CLOSED: [2026-01-22 Wed 11:15]
-:LOGBOOK:
-- State "DONE"       from "STRT"       [2026-01-22 Wed 11:15]
-- State "STRT"       from "TODO"       [2026-01-22 Wed 09:00]
-CLOCK: [2026-01-22 Wed 09:00]--[2026-01-22 Wed 11:15] =>  2:15
-:END:
-
-Fixed the authentication bug.
-
-** TODO Pending task (should not appear)
-SCHEDULED: <2026-01-28 Tue>
-
-This is a pending task.
-
-* Projects
-** DONE Keyboard firmware update
-CLOSED: [2026-01-15 Wed 18:00]
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-15 Wed 18:00]
-:END:
-
-Updated firmware for both keyboards.
-`
-	filePath := filepath.Join(dir, "todos.org")
-	if err := os.WriteFile(filePath, []byte(content), 0o644); err != nil {
-		t.Fatalf("failed to write test org file: %v", err)
-	}
-
-	return filePath
-}
-
-func TestOrgSource_ParsesStateChanges(t *testing.T) {
-	filePath := setupTestOrgFile(t)
-
-	cfg := &config.OrgConfig{
-		Enabled:             true,
-		Files:               []string{filePath},
-		IncludeDone:         true,
-		IncludeStateChanges: true,
-		IncludeClockEntries: false,
-	}
-
-	source := NewOrgSource(cfg)
-
-	// Query for late January 2026
-	start := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 26, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	// Should find 2 items (the 2 that were marked DONE in range)
-	// Not the one from Jan 15 (out of range) or pending task
-	if len(act.Items) < 2 {
-		t.Errorf("expected at least 2 items, got %d", len(act.Items))
-		for _, item := range act.Items {
-			t.Logf("  %s: %s (%s)", item.Type, item.Title, item.Timestamp.Format("2006-01-02"))
-		}
-	}
-
-	// Check for specific items
-	foundReviewPR := false
-	foundAuthBug := false
-	for _, item := range act.Items {
-		if item.Title == "Review PR for feature X" {
-			foundReviewPR = true
-			if item.Timestamp.Day() != 25 {
-				t.Errorf("Review PR date = %d, want 25", item.Timestamp.Day())
-			}
-		}
-		if item.Title == "Fix critical bug in authentication" {
-			foundAuthBug = true
-			if item.Timestamp.Day() != 22 {
-				t.Errorf("Auth bug date = %d, want 22", item.Timestamp.Day())
-			}
-		}
-	}
-
-	if !foundReviewPR {
-		t.Error("did not find 'Review PR for feature X'")
-	}
-	if !foundAuthBug {
-		t.Error("did not find 'Fix critical bug in authentication'")
-	}
-}
-
-func TestOrgSource_ParsesClockEntries(t *testing.T) {
-	filePath := setupTestOrgFile(t)
-
-	cfg := &config.OrgConfig{
-		Enabled:             true,
-		Files:               []string{filePath},
-		IncludeDone:         false,
-		IncludeStateChanges: false,
-		IncludeClockEntries: true,
-	}
-
-	source := NewOrgSource(cfg)
-
-	start := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 26, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	// Should find 1 clock entry
-	if len(act.Items) != 1 {
-		t.Errorf("expected 1 clock entry, got %d", len(act.Items))
-		for _, item := range act.Items {
-			t.Logf("  %s: %s (%s)", item.Type, item.Title, item.Timestamp.Format("2006-01-02"))
-		}
-		return
-	}
-
-	item := act.Items[0]
-	if item.Type != "clock_entry" {
-		t.Errorf("Type = %q, want %q", item.Type, "clock_entry")
-	}
-	if item.Metadata["duration"] != "2:15" {
-		t.Errorf("duration = %q, want %q", item.Metadata["duration"], "2:15")
-	}
-}
-
-func TestOrgSource_FiltersOutsideDateRange(t *testing.T) {
-	filePath := setupTestOrgFile(t)
-
-	cfg := &config.OrgConfig{
-		Enabled:             true,
-		Files:               []string{filePath},
-		IncludeDone:         true,
-		IncludeStateChanges: true,
-		IncludeClockEntries: true,
-	}
-
-	source := NewOrgSource(cfg)
-
-	// Query for December 2025 - should return nothing
-	start := time.Date(2025, 12, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2025, 12, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	if len(act.Items) != 0 {
-		t.Errorf("expected 0 items outside date range, got %d", len(act.Items))
-	}
-}
-
-func TestOrgSource_ExtractsHeadingTitle(t *testing.T) {
-	filePath := setupTestOrgFile(t)
-
-	cfg := &config.OrgConfig{
-		Enabled:             true,
-		Files:               []string{filePath},
-		IncludeDone:         true,
-		IncludeStateChanges: true,
-		IncludeClockEntries: false,
-	}
-
-	source := NewOrgSource(cfg)
-
-	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	// All items should have cleaned titles (no TODO state, no priority)
-	for _, item := range act.Items {
-		if item.Title == "" {
-			t.Error("found item with empty title")
-		}
-		// Title should not contain TODO/DONE keywords
-		if containsKeyword(item.Title) {
-			t.Errorf("title contains org keyword: %q", item.Title)
-		}
-	}
-}
-
-func containsKeyword(s string) bool {
-	keywords := []string{"TODO", "DONE", "STRT", "NEXT", "WAIT", "CANX"}
-	for _, kw := range keywords {
-		if len(s) >= len(kw) && s[:len(kw)] == kw {
-			return true
-		}
-	}
-	return false
-}
-
-func TestOrgSource_ParsesArchiveDirectory(t *testing.T) {
-	// Create main org file
-	mainDir := t.TempDir()
-	mainContent := `#+title: Main TODOs
-
-* Work
-** DONE Main task done this week
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-25 Sat 10:00]
-:END:
-`
-	mainFile := filepath.Join(mainDir, "todos.org")
-	if err := os.WriteFile(mainFile, []byte(mainContent), 0o644); err != nil {
-		t.Fatalf("failed to write main org file: %v", err)
-	}
-
-	// Create archive directory with archived TODOs
-	archiveDir := filepath.Join(mainDir, "archive")
-	if err := os.MkdirAll(archiveDir, 0o755); err != nil {
-		t.Fatalf("failed to create archive directory: %v", err)
-	}
-
-	// Archive file WITH .org extension
-	archiveContent := `#+title: Archived Work
-
-* Archived
-** DONE Archived task from last week
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-22 Wed 14:30]
-:END:
-`
-	archiveFile := filepath.Join(archiveDir, "work.org")
-	if err := os.WriteFile(archiveFile, []byte(archiveContent), 0o644); err != nil {
-		t.Fatalf("failed to write archive org file: %v", err)
-	}
-
-	// Archive file WITHOUT extension (common org-mode archive format)
-	noExtContent := `#    -*- mode: org -*-
-
-Archived entries from file /home/user/todos.org
-
-* DONE Task from extensionless archive
-CLOSED: [2026-01-23 Thu 16:00]
-:PROPERTIES:
-:ARCHIVE_TIME: 2026-01-23 Thu 16:00
-:END:
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-23 Thu 16:00]
-:END:
-`
-	noExtFile := filepath.Join(archiveDir, "work")
-	if err := os.WriteFile(noExtFile, []byte(noExtContent), 0o644); err != nil {
-		t.Fatalf("failed to write extensionless archive file: %v", err)
-	}
-
-	cfg := &config.OrgConfig{
-		Enabled:             true,
-		Files:               []string{mainFile},
-		ArchiveDir:          archiveDir,
-		IncludeDone:         true,
-		IncludeStateChanges: true,
-		IncludeClockEntries: false,
-	}
-
-	source := NewOrgSource(cfg)
-
-	start := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 26, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	// Should find all 3 tasks: main + .org archive + extensionless archive
-	if len(act.Items) != 3 {
-		t.Errorf("expected 3 items (main + 2 archives), got %d", len(act.Items))
-		for _, item := range act.Items {
-			t.Logf("  %s: %s (%s)", item.Type, item.Title, item.Timestamp.Format("2006-01-02"))
-		}
-		return
-	}
-
-	// Check for all tasks
-	foundMain := false
-	foundArchived := false
-	foundNoExt := false
-	for _, item := range act.Items {
-		if item.Title == "Main task done this week" {
-			foundMain = true
-		}
-		if item.Title == "Archived task from last week" {
-			foundArchived = true
-		}
-		if item.Title == "Task from extensionless archive" {
-			foundNoExt = true
-		}
-	}
-
-	if !foundMain {
-		t.Error("did not find main task")
-	}
-	if !foundArchived {
-		t.Error("did not find archived task (.org)")
-	}
-	if !foundNoExt {
-		t.Error("did not find task from extensionless archive")
-	}
-}
-
-func TestOrgSource_TracksSection(t *testing.T) {
-	dir := t.TempDir()
-	content := `#+title: Test TODOs
-
-* Work
-** DONE Task in Work section
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-25 Sat 10:00]
-:END:
-
-* Systems
-** DONE Task in Systems section
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-25 Sat 11:00]
-:END:
-
-* Projects
-** DONE Task in Projects section
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-25 Sat 12:00]
-:END:
-`
-	filePath := filepath.Join(dir, "todos.org")
-	if err := os.WriteFile(filePath, []byte(content), 0o644); err != nil {
-		t.Fatalf("failed to write test org file: %v", err)
-	}
-
-	cfg := &config.OrgConfig{
-		Enabled:             true,
-		Files:               []string{filePath},
-		IncludeDone:         true,
-		IncludeStateChanges: true,
-	}
-
-	source := NewOrgSource(cfg)
-	start := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 26, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	if len(act.Items) != 3 {
-		t.Fatalf("expected 3 items, got %d", len(act.Items))
-	}
-
-	// Check section metadata
-	sections := make(map[string]string)
-	for _, item := range act.Items {
-		sections[item.Title] = item.Metadata["section"]
-	}
-
-	if sections["Task in Work section"] != "Work" {
-		t.Errorf("Work task section = %q, want %q", sections["Task in Work section"], "Work")
-	}
-	if sections["Task in Systems section"] != "Systems" {
-		t.Errorf("Systems task section = %q, want %q", sections["Task in Systems section"], "Systems")
-	}
-	if sections["Task in Projects section"] != "Projects" {
-		t.Errorf("Projects task section = %q, want %q", sections["Task in Projects section"], "Projects")
-	}
-}
-
-func TestOrgSource_ConvertsOrgLinksToMarkdown(t *testing.T) {
-	dir := t.TempDir()
-	content := `#+title: Test TODOs
-
-* Work
-** DONE Review [[https://github.com/org/repo/pull/123][PR #123 for feature]]
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-25 Sat 10:00]
-:END:
-
-** DONE Check [[https://example.com]]
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-25 Sat 11:00]
-:END:
-
-** DONE Look at [[file:notes.org][my notes]] and [[https://docs.example.com][docs]]
-:LOGBOOK:
-- State "DONE"       from "TODO"       [2026-01-25 Sat 12:00]
-:END:
-`
-	filePath := filepath.Join(dir, "todos.org")
-	if err := os.WriteFile(filePath, []byte(content), 0o644); err != nil {
-		t.Fatalf("failed to write test org file: %v", err)
-	}
-
-	cfg := &config.OrgConfig{
-		Enabled:             true,
-		Files:               []string{filePath},
-		IncludeDone:         true,
-		IncludeStateChanges: true,
-	}
-
-	source := NewOrgSource(cfg)
-	start := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
-	end := time.Date(2026, 1, 26, 23, 59, 59, 0, time.UTC)
-
-	act, err := source.Fetch(t.Context(), start, end)
-	if err != nil {
-		t.Fatalf("Fetch() error = %v", err)
-	}
-
-	if len(act.Items) != 3 {
-		t.Fatalf("expected 3 items, got %d", len(act.Items))
-	}
-
-	// Check link conversion
-	titles := make(map[string]bool)
-	for _, item := range act.Items {
-		titles[item.Title] = true
-		t.Logf("Title: %s", item.Title)
-	}
-
-	// [[url][desc]] -> [desc](url)
-	if !titles["Review [PR #123 for feature](https://github.com/org/repo/pull/123)"] {
-		t.Error("expected link with description to be converted")
-	}
-
-	// [[url]] -> [url](url)
-	if !titles["Check [https://example.com](https://example.com)"] {
-		t.Error("expected bare link to be converted")
-	}
-
-	// Multiple links in one title
-	if !titles["Look at [my notes](file:notes.org) and [docs](https://docs.example.com)"] {
-		t.Error("expected multiple links to be converted")
-	}
-}
-
-func TestConvertOrgLinksToMarkdown(t *testing.T) {
-	tests := []struct {
-		input    string
-		expected string
-	}{
-		// Link with description
-		{"[[https://example.com][Example]]", "[Example](https://example.com)"},
-		// Bare link
-		{"[[https://example.com]]", "[https://example.com](https://example.com)"},
-		// Multiple links
-		{"Check [[https://a.com][A]] and [[https://b.com][B]]", "Check [A](https://a.com) and [B](https://b.com)"},
-		// File link
-		{"[[file:notes.org][Notes]]", "[Notes](file:notes.org)"},
-		// No links
-		{"Plain text without links", "Plain text without links"},
-		// Denote link
-		{"[[denote:20250312T050706][Vibhav Bobade]]", "[Vibhav Bobade](denote:20250312T050706)"},
-	}
-
-	for _, tt := range tests {
-		got := convertOrgLinksToMarkdown(tt.input)
-		if got != tt.expected {
-			t.Errorf("convertOrgLinksToMarkdown(%q) = %q, want %q", tt.input, got, tt.expected)
-		}
-	}
-}
tools/review-tool/internal/sources/source.go
@@ -1,126 +0,0 @@
-// Package sources provides data source implementations.
-package sources
-
-import (
-	"context"
-	"sync"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-	"github.com/vdemeester/home/tools/review-tool/internal/config"
-)
-
-// Source defines the interface for activity data sources.
-type Source interface {
-	// Name returns the source identifier.
-	Name() string
-
-	// Fetch retrieves activities within the given time range.
-	Fetch(ctx context.Context, start, end time.Time) (*activity.Activity, error)
-
-	// Validate checks if the source is properly configured.
-	Validate() error
-}
-
-// Registry holds all available sources.
-type Registry struct {
-	sources map[string]Source
-}
-
-// NewRegistry creates a registry with sources based on configuration.
-func NewRegistry(cfg *config.Config) *Registry {
-	r := &Registry{sources: make(map[string]Source)}
-
-	if cfg.GitHub.Enabled {
-		r.sources["github"] = NewGitHubSource(&cfg.GitHub)
-	}
-	if cfg.Org.Enabled {
-		r.sources["org"] = NewOrgSource(&cfg.Org)
-	}
-	if cfg.Jira.Enabled {
-		r.sources["jira"] = NewJiraSource(&cfg.Jira)
-	}
-	if cfg.AI.Enabled {
-		r.sources["ai"] = NewAISource(&cfg.AI)
-	}
-
-	return r
-}
-
-// Sources returns the list of registered source names.
-func (r *Registry) Sources() []string {
-	names := make([]string, 0, len(r.sources))
-	for name := range r.sources {
-		names = append(names, name)
-	}
-	return names
-}
-
-// Get returns a source by name.
-func (r *Registry) Get(name string) (Source, bool) {
-	s, ok := r.sources[name]
-	return s, ok
-}
-
-// FetchAll runs all sources concurrently and returns results.
-func (r *Registry) FetchAll(ctx context.Context, start, end time.Time) map[string]*activity.Activity {
-	results := make(map[string]*activity.Activity)
-	var mu sync.Mutex
-	var wg sync.WaitGroup
-
-	for name, source := range r.sources {
-		wg.Add(1)
-		go func(name string, source Source) {
-			defer wg.Done()
-
-			act, err := source.Fetch(ctx, start, end)
-			if err != nil {
-				act = &activity.Activity{
-					Source: name,
-					Error:  err.Error(),
-				}
-			}
-
-			mu.Lock()
-			results[name] = act
-			mu.Unlock()
-		}(name, source)
-	}
-
-	wg.Wait()
-	return results
-}
-
-// FetchSelected runs only the specified sources.
-func (r *Registry) FetchSelected(ctx context.Context, start, end time.Time, names []string) map[string]*activity.Activity {
-	results := make(map[string]*activity.Activity)
-	var mu sync.Mutex
-	var wg sync.WaitGroup
-
-	for _, name := range names {
-		source, ok := r.sources[name]
-		if !ok {
-			continue
-		}
-
-		wg.Add(1)
-		go func(name string, source Source) {
-			defer wg.Done()
-
-			act, err := source.Fetch(ctx, start, end)
-			if err != nil {
-				act = &activity.Activity{
-					Source: name,
-					Error:  err.Error(),
-				}
-			}
-
-			mu.Lock()
-			results[name] = act
-			mu.Unlock()
-		}(name, source)
-	}
-
-	wg.Wait()
-	return results
-}
tools/review-tool/internal/timerange/timerange.go
@@ -1,144 +0,0 @@
-// Package timerange provides natural language time range parsing.
-package timerange
-
-import (
-	"fmt"
-	"regexp"
-	"strconv"
-	"strings"
-	"time"
-
-	"github.com/vdemeester/home/tools/review-tool/internal/activity"
-)
-
-var (
-	pastRe      = regexp.MustCompile(`^past\s+(\d+)\s+(day|days|week|weeks|month|months)$`)
-	lastNRe     = regexp.MustCompile(`^last\s+(\d+)\s+(day|days|week|weeks|month|months)$`)
-	dateRangeRe = regexp.MustCompile(`^(\d{4}-\d{2}-\d{2})\.\.(\d{4}-\d{2}-\d{2})$`)
-)
-
-// Parse converts natural language to a time range.
-func Parse(input string) (*activity.TimeRange, error) {
-	input = strings.ToLower(strings.TrimSpace(input))
-	now := time.Now()
-
-	switch input {
-	case "today":
-		start := startOfDay(now)
-		return &activity.TimeRange{Start: start, End: now, Description: "today"}, nil
-
-	case "yesterday":
-		yesterday := now.AddDate(0, 0, -1)
-		return &activity.TimeRange{
-			Start:       startOfDay(yesterday),
-			End:         endOfDay(yesterday),
-			Description: "yesterday",
-		}, nil
-
-	case "this week":
-		start := startOfWeek(now)
-		return &activity.TimeRange{Start: start, End: now, Description: "this week"}, nil
-
-	case "last week":
-		thisWeekStart := startOfWeek(now)
-		lastWeekStart := thisWeekStart.AddDate(0, 0, -7)
-		return &activity.TimeRange{
-			Start:       lastWeekStart,
-			End:         thisWeekStart.Add(-time.Second),
-			Description: "last week",
-		}, nil
-
-	case "this month":
-		start := startOfMonth(now)
-		return &activity.TimeRange{Start: start, End: now, Description: "this month"}, nil
-
-	case "last month":
-		thisMonthStart := startOfMonth(now)
-		lastMonthStart := thisMonthStart.AddDate(0, -1, 0)
-		return &activity.TimeRange{
-			Start:       lastMonthStart,
-			End:         thisMonthStart.Add(-time.Second),
-			Description: "last month",
-		}, nil
-	}
-
-	// Try "past N days/weeks/months"
-	if matches := pastRe.FindStringSubmatch(input); len(matches) == 3 {
-		return parseDuration(matches[1], matches[2], now, input)
-	}
-
-	// Try "last N days/weeks/months"
-	if matches := lastNRe.FindStringSubmatch(input); len(matches) == 3 {
-		return parseDuration(matches[1], matches[2], now, input)
-	}
-
-	// Try date range "2026-01-01..2026-01-15"
-	if matches := dateRangeRe.FindStringSubmatch(input); len(matches) == 3 {
-		return parseDateRange(matches[1], matches[2])
-	}
-
-	return nil, fmt.Errorf("unrecognized time range: %q", input)
-}
-
-func parseDuration(nStr, unit string, now time.Time, desc string) (*activity.TimeRange, error) {
-	n, err := strconv.Atoi(nStr)
-	if err != nil {
-		return nil, fmt.Errorf("invalid number: %s", nStr)
-	}
-
-	var start time.Time
-	switch {
-	case strings.HasPrefix(unit, "day"):
-		start = now.AddDate(0, 0, -n)
-	case strings.HasPrefix(unit, "week"):
-		start = now.AddDate(0, 0, -7*n)
-	case strings.HasPrefix(unit, "month"):
-		start = now.AddDate(0, -n, 0)
-	default:
-		return nil, fmt.Errorf("unknown unit: %s", unit)
-	}
-
-	return &activity.TimeRange{
-		Start:       startOfDay(start),
-		End:         now,
-		Description: desc,
-	}, nil
-}
-
-func parseDateRange(startStr, endStr string) (*activity.TimeRange, error) {
-	start, err := time.Parse("2006-01-02", startStr)
-	if err != nil {
-		return nil, fmt.Errorf("invalid start date: %w", err)
-	}
-
-	end, err := time.Parse("2006-01-02", endStr)
-	if err != nil {
-		return nil, fmt.Errorf("invalid end date: %w", err)
-	}
-
-	return &activity.TimeRange{
-		Start:       startOfDay(start),
-		End:         endOfDay(end),
-		Description: fmt.Sprintf("%s to %s", startStr, endStr),
-	}, nil
-}
-
-func startOfDay(t time.Time) time.Time {
-	return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
-}
-
-func endOfDay(t time.Time) time.Time {
-	return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
-}
-
-func startOfWeek(t time.Time) time.Time {
-	weekday := int(t.Weekday())
-	if weekday == 0 {
-		weekday = 7 // Sunday is 7, not 0
-	}
-	return startOfDay(t.AddDate(0, 0, -weekday+1)) // Monday
-}
-
-func startOfMonth(t time.Time) time.Time {
-	return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
-}
tools/review-tool/internal/timerange/timerange_integration_test.go
@@ -1,40 +0,0 @@
-package timerange
-
-import (
-	"testing"
-	"time"
-)
-
-func TestParse_PastDays_Boundaries(t *testing.T) {
-	tr, err := Parse("past 7 days")
-	if err != nil {
-		t.Fatalf("Parse error: %v", err)
-	}
-
-	t.Logf("Start: %v", tr.Start)
-	t.Logf("End: %v", tr.End)
-
-	// A date 3 days ago (formatted as YYYY-MM-DD, parsed as UTC midnight)
-	// must fall within "past 7 days".
-	threeDaysAgo := time.Now().AddDate(0, 0, -3)
-	dateStr := threeDaysAgo.Format("2006-01-02")
-	testDate, _ := time.Parse("2006-01-02", dateStr)
-	t.Logf("Test date (%s parsed): %v", dateStr, testDate)
-
-	inRange := !testDate.Before(tr.Start) && !testDate.After(tr.End)
-	t.Logf("%s in range? %v", dateStr, inRange)
-
-	if !inRange {
-		t.Errorf("Expected %s to be in range for past 7 days", dateStr)
-	}
-
-	// A date 10 days ago should NOT be in range
-	tenDaysAgo := time.Now().AddDate(0, 0, -10)
-	dateStr2 := tenDaysAgo.Format("2006-01-02")
-	testDate2, _ := time.Parse("2006-01-02", dateStr2)
-
-	inRange2 := !testDate2.Before(tr.Start) && !testDate2.After(tr.End)
-	if inRange2 {
-		t.Errorf("Expected %s to NOT be in range for past 7 days", dateStr2)
-	}
-}
tools/review-tool/internal/timerange/timerange_test.go
@@ -1,77 +0,0 @@
-package timerange
-
-import (
-	"testing"
-	"time"
-)
-
-func TestParse(t *testing.T) {
-	tests := []struct {
-		input   string
-		wantErr bool
-	}{
-		{"today", false},
-		{"yesterday", false},
-		{"this week", false},
-		{"last week", false},
-		{"this month", false},
-		{"last month", false},
-		{"past 3 days", false},
-		{"past 2 weeks", false},
-		{"past 1 month", false},
-		{"last 7 days", false},
-		{"last 2 weeks", false},
-		{"2026-01-01..2026-01-15", false},
-		{"invalid", true},
-		{"past days", true},
-		{"", true},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.input, func(t *testing.T) {
-			tr, err := Parse(tt.input)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Parse(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
-				return
-			}
-			if !tt.wantErr {
-				if tr == nil {
-					t.Errorf("Parse(%q) returned nil TimeRange", tt.input)
-					return
-				}
-				if tr.Start.After(tr.End) {
-					t.Errorf("Parse(%q) Start %v is after End %v", tt.input, tr.Start, tr.End)
-				}
-				if tr.Description == "" {
-					t.Errorf("Parse(%q) has empty Description", tt.input)
-				}
-			}
-		})
-	}
-}
-
-func TestStartOfWeek(t *testing.T) {
-	// Test that Monday is the start of week
-	wed := time.Date(2026, 1, 28, 15, 30, 0, 0, time.Local) // Wednesday
-	start := startOfWeek(wed)
-	if start.Weekday() != time.Monday {
-		t.Errorf("startOfWeek returned %v, want Monday", start.Weekday())
-	}
-	if start.Day() != 26 {
-		t.Errorf("startOfWeek returned day %d, want 26", start.Day())
-	}
-}
-
-func TestDateRange(t *testing.T) {
-	tr, err := Parse("2026-01-10..2026-01-20")
-	if err != nil {
-		t.Fatalf("Parse date range failed: %v", err)
-	}
-
-	if tr.Start.Day() != 10 || tr.Start.Month() != 1 || tr.Start.Year() != 2026 {
-		t.Errorf("Start date wrong: %v", tr.Start)
-	}
-	if tr.End.Day() != 20 || tr.End.Month() != 1 || tr.End.Year() != 2026 {
-		t.Errorf("End date wrong: %v", tr.End)
-	}
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/apic.go
@@ -1,747 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
-	"io"
-)
-
-func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
-	//fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
-
-	// Check if we can move the queue at the beginning of the buffer.
-	if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
-		if parser.tokens_head != len(parser.tokens) {
-			copy(parser.tokens, parser.tokens[parser.tokens_head:])
-		}
-		parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
-		parser.tokens_head = 0
-	}
-	parser.tokens = append(parser.tokens, *token)
-	if pos < 0 {
-		return
-	}
-	copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
-	parser.tokens[parser.tokens_head+pos] = *token
-}
-
-// Create a new parser object.
-func yaml_parser_initialize(parser *yaml_parser_t) bool {
-	*parser = yaml_parser_t{
-		raw_buffer: make([]byte, 0, input_raw_buffer_size),
-		buffer:     make([]byte, 0, input_buffer_size),
-	}
-	return true
-}
-
-// Destroy a parser object.
-func yaml_parser_delete(parser *yaml_parser_t) {
-	*parser = yaml_parser_t{}
-}
-
-// String read handler.
-func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
-	if parser.input_pos == len(parser.input) {
-		return 0, io.EOF
-	}
-	n = copy(buffer, parser.input[parser.input_pos:])
-	parser.input_pos += n
-	return n, nil
-}
-
-// Reader read handler.
-func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
-	return parser.input_reader.Read(buffer)
-}
-
-// Set a string input.
-func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
-	if parser.read_handler != nil {
-		panic("must set the input source only once")
-	}
-	parser.read_handler = yaml_string_read_handler
-	parser.input = input
-	parser.input_pos = 0
-}
-
-// Set a file input.
-func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
-	if parser.read_handler != nil {
-		panic("must set the input source only once")
-	}
-	parser.read_handler = yaml_reader_read_handler
-	parser.input_reader = r
-}
-
-// Set the source encoding.
-func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
-	if parser.encoding != yaml_ANY_ENCODING {
-		panic("must set the encoding only once")
-	}
-	parser.encoding = encoding
-}
-
-// Create a new emitter object.
-func yaml_emitter_initialize(emitter *yaml_emitter_t) {
-	*emitter = yaml_emitter_t{
-		buffer:     make([]byte, output_buffer_size),
-		raw_buffer: make([]byte, 0, output_raw_buffer_size),
-		states:     make([]yaml_emitter_state_t, 0, initial_stack_size),
-		events:     make([]yaml_event_t, 0, initial_queue_size),
-		best_width: -1,
-	}
-}
-
-// Destroy an emitter object.
-func yaml_emitter_delete(emitter *yaml_emitter_t) {
-	*emitter = yaml_emitter_t{}
-}
-
-// String write handler.
-func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
-	*emitter.output_buffer = append(*emitter.output_buffer, buffer...)
-	return nil
-}
-
-// yaml_writer_write_handler uses emitter.output_writer to write the
-// emitted text.
-func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
-	_, err := emitter.output_writer.Write(buffer)
-	return err
-}
-
-// Set a string output.
-func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
-	if emitter.write_handler != nil {
-		panic("must set the output target only once")
-	}
-	emitter.write_handler = yaml_string_write_handler
-	emitter.output_buffer = output_buffer
-}
-
-// Set a file output.
-func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
-	if emitter.write_handler != nil {
-		panic("must set the output target only once")
-	}
-	emitter.write_handler = yaml_writer_write_handler
-	emitter.output_writer = w
-}
-
-// Set the output encoding.
-func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
-	if emitter.encoding != yaml_ANY_ENCODING {
-		panic("must set the output encoding only once")
-	}
-	emitter.encoding = encoding
-}
-
-// Set the canonical output style.
-func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
-	emitter.canonical = canonical
-}
-
-// Set the indentation increment.
-func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
-	if indent < 2 || indent > 9 {
-		indent = 2
-	}
-	emitter.best_indent = indent
-}
-
-// Set the preferred line width.
-func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
-	if width < 0 {
-		width = -1
-	}
-	emitter.best_width = width
-}
-
-// Set if unescaped non-ASCII characters are allowed.
-func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
-	emitter.unicode = unicode
-}
-
-// Set the preferred line break character.
-func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
-	emitter.line_break = line_break
-}
-
-///*
-// * Destroy a token object.
-// */
-//
-//YAML_DECLARE(void)
-//yaml_token_delete(yaml_token_t *token)
-//{
-//    assert(token);  // Non-NULL token object expected.
-//
-//    switch (token.type)
-//    {
-//        case YAML_TAG_DIRECTIVE_TOKEN:
-//            yaml_free(token.data.tag_directive.handle);
-//            yaml_free(token.data.tag_directive.prefix);
-//            break;
-//
-//        case YAML_ALIAS_TOKEN:
-//            yaml_free(token.data.alias.value);
-//            break;
-//
-//        case YAML_ANCHOR_TOKEN:
-//            yaml_free(token.data.anchor.value);
-//            break;
-//
-//        case YAML_TAG_TOKEN:
-//            yaml_free(token.data.tag.handle);
-//            yaml_free(token.data.tag.suffix);
-//            break;
-//
-//        case YAML_SCALAR_TOKEN:
-//            yaml_free(token.data.scalar.value);
-//            break;
-//
-//        default:
-//            break;
-//    }
-//
-//    memset(token, 0, sizeof(yaml_token_t));
-//}
-//
-///*
-// * Check if a string is a valid UTF-8 sequence.
-// *
-// * Check 'reader.c' for more details on UTF-8 encoding.
-// */
-//
-//static int
-//yaml_check_utf8(yaml_char_t *start, size_t length)
-//{
-//    yaml_char_t *end = start+length;
-//    yaml_char_t *pointer = start;
-//
-//    while (pointer < end) {
-//        unsigned char octet;
-//        unsigned int width;
-//        unsigned int value;
-//        size_t k;
-//
-//        octet = pointer[0];
-//        width = (octet & 0x80) == 0x00 ? 1 :
-//                (octet & 0xE0) == 0xC0 ? 2 :
-//                (octet & 0xF0) == 0xE0 ? 3 :
-//                (octet & 0xF8) == 0xF0 ? 4 : 0;
-//        value = (octet & 0x80) == 0x00 ? octet & 0x7F :
-//                (octet & 0xE0) == 0xC0 ? octet & 0x1F :
-//                (octet & 0xF0) == 0xE0 ? octet & 0x0F :
-//                (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
-//        if (!width) return 0;
-//        if (pointer+width > end) return 0;
-//        for (k = 1; k < width; k ++) {
-//            octet = pointer[k];
-//            if ((octet & 0xC0) != 0x80) return 0;
-//            value = (value << 6) + (octet & 0x3F);
-//        }
-//        if (!((width == 1) ||
-//            (width == 2 && value >= 0x80) ||
-//            (width == 3 && value >= 0x800) ||
-//            (width == 4 && value >= 0x10000))) return 0;
-//
-//        pointer += width;
-//    }
-//
-//    return 1;
-//}
-//
-
-// Create STREAM-START.
-func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
-	*event = yaml_event_t{
-		typ:      yaml_STREAM_START_EVENT,
-		encoding: encoding,
-	}
-}
-
-// Create STREAM-END.
-func yaml_stream_end_event_initialize(event *yaml_event_t) {
-	*event = yaml_event_t{
-		typ: yaml_STREAM_END_EVENT,
-	}
-}
-
-// Create DOCUMENT-START.
-func yaml_document_start_event_initialize(
-	event *yaml_event_t,
-	version_directive *yaml_version_directive_t,
-	tag_directives []yaml_tag_directive_t,
-	implicit bool,
-) {
-	*event = yaml_event_t{
-		typ:               yaml_DOCUMENT_START_EVENT,
-		version_directive: version_directive,
-		tag_directives:    tag_directives,
-		implicit:          implicit,
-	}
-}
-
-// Create DOCUMENT-END.
-func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
-	*event = yaml_event_t{
-		typ:      yaml_DOCUMENT_END_EVENT,
-		implicit: implicit,
-	}
-}
-
-// Create ALIAS.
-func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) bool {
-	*event = yaml_event_t{
-		typ:    yaml_ALIAS_EVENT,
-		anchor: anchor,
-	}
-	return true
-}
-
-// Create SCALAR.
-func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
-	*event = yaml_event_t{
-		typ:             yaml_SCALAR_EVENT,
-		anchor:          anchor,
-		tag:             tag,
-		value:           value,
-		implicit:        plain_implicit,
-		quoted_implicit: quoted_implicit,
-		style:           yaml_style_t(style),
-	}
-	return true
-}
-
-// Create SEQUENCE-START.
-func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
-	*event = yaml_event_t{
-		typ:      yaml_SEQUENCE_START_EVENT,
-		anchor:   anchor,
-		tag:      tag,
-		implicit: implicit,
-		style:    yaml_style_t(style),
-	}
-	return true
-}
-
-// Create SEQUENCE-END.
-func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
-	*event = yaml_event_t{
-		typ: yaml_SEQUENCE_END_EVENT,
-	}
-	return true
-}
-
-// Create MAPPING-START.
-func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
-	*event = yaml_event_t{
-		typ:      yaml_MAPPING_START_EVENT,
-		anchor:   anchor,
-		tag:      tag,
-		implicit: implicit,
-		style:    yaml_style_t(style),
-	}
-}
-
-// Create MAPPING-END.
-func yaml_mapping_end_event_initialize(event *yaml_event_t) {
-	*event = yaml_event_t{
-		typ: yaml_MAPPING_END_EVENT,
-	}
-}
-
-// Destroy an event object.
-func yaml_event_delete(event *yaml_event_t) {
-	*event = yaml_event_t{}
-}
-
-///*
-// * Create a document object.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_initialize(document *yaml_document_t,
-//        version_directive *yaml_version_directive_t,
-//        tag_directives_start *yaml_tag_directive_t,
-//        tag_directives_end *yaml_tag_directive_t,
-//        start_implicit int, end_implicit int)
-//{
-//    struct {
-//        error yaml_error_type_t
-//    } context
-//    struct {
-//        start *yaml_node_t
-//        end *yaml_node_t
-//        top *yaml_node_t
-//    } nodes = { NULL, NULL, NULL }
-//    version_directive_copy *yaml_version_directive_t = NULL
-//    struct {
-//        start *yaml_tag_directive_t
-//        end *yaml_tag_directive_t
-//        top *yaml_tag_directive_t
-//    } tag_directives_copy = { NULL, NULL, NULL }
-//    value yaml_tag_directive_t = { NULL, NULL }
-//    mark yaml_mark_t = { 0, 0, 0 }
-//
-//    assert(document) // Non-NULL document object is expected.
-//    assert((tag_directives_start && tag_directives_end) ||
-//            (tag_directives_start == tag_directives_end))
-//                            // Valid tag directives are expected.
-//
-//    if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
-//
-//    if (version_directive) {
-//        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
-//        if (!version_directive_copy) goto error
-//        version_directive_copy.major = version_directive.major
-//        version_directive_copy.minor = version_directive.minor
-//    }
-//
-//    if (tag_directives_start != tag_directives_end) {
-//        tag_directive *yaml_tag_directive_t
-//        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
-//            goto error
-//        for (tag_directive = tag_directives_start
-//                tag_directive != tag_directives_end; tag_directive ++) {
-//            assert(tag_directive.handle)
-//            assert(tag_directive.prefix)
-//            if (!yaml_check_utf8(tag_directive.handle,
-//                        strlen((char *)tag_directive.handle)))
-//                goto error
-//            if (!yaml_check_utf8(tag_directive.prefix,
-//                        strlen((char *)tag_directive.prefix)))
-//                goto error
-//            value.handle = yaml_strdup(tag_directive.handle)
-//            value.prefix = yaml_strdup(tag_directive.prefix)
-//            if (!value.handle || !value.prefix) goto error
-//            if (!PUSH(&context, tag_directives_copy, value))
-//                goto error
-//            value.handle = NULL
-//            value.prefix = NULL
-//        }
-//    }
-//
-//    DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
-//            tag_directives_copy.start, tag_directives_copy.top,
-//            start_implicit, end_implicit, mark, mark)
-//
-//    return 1
-//
-//error:
-//    STACK_DEL(&context, nodes)
-//    yaml_free(version_directive_copy)
-//    while (!STACK_EMPTY(&context, tag_directives_copy)) {
-//        value yaml_tag_directive_t = POP(&context, tag_directives_copy)
-//        yaml_free(value.handle)
-//        yaml_free(value.prefix)
-//    }
-//    STACK_DEL(&context, tag_directives_copy)
-//    yaml_free(value.handle)
-//    yaml_free(value.prefix)
-//
-//    return 0
-//}
-//
-///*
-// * Destroy a document object.
-// */
-//
-//YAML_DECLARE(void)
-//yaml_document_delete(document *yaml_document_t)
-//{
-//    struct {
-//        error yaml_error_type_t
-//    } context
-//    tag_directive *yaml_tag_directive_t
-//
-//    context.error = YAML_NO_ERROR // Eliminate a compiler warning.
-//
-//    assert(document) // Non-NULL document object is expected.
-//
-//    while (!STACK_EMPTY(&context, document.nodes)) {
-//        node yaml_node_t = POP(&context, document.nodes)
-//        yaml_free(node.tag)
-//        switch (node.type) {
-//            case YAML_SCALAR_NODE:
-//                yaml_free(node.data.scalar.value)
-//                break
-//            case YAML_SEQUENCE_NODE:
-//                STACK_DEL(&context, node.data.sequence.items)
-//                break
-//            case YAML_MAPPING_NODE:
-//                STACK_DEL(&context, node.data.mapping.pairs)
-//                break
-//            default:
-//                assert(0) // Should not happen.
-//        }
-//    }
-//    STACK_DEL(&context, document.nodes)
-//
-//    yaml_free(document.version_directive)
-//    for (tag_directive = document.tag_directives.start
-//            tag_directive != document.tag_directives.end
-//            tag_directive++) {
-//        yaml_free(tag_directive.handle)
-//        yaml_free(tag_directive.prefix)
-//    }
-//    yaml_free(document.tag_directives.start)
-//
-//    memset(document, 0, sizeof(yaml_document_t))
-//}
-//
-///**
-// * Get a document node.
-// */
-//
-//YAML_DECLARE(yaml_node_t *)
-//yaml_document_get_node(document *yaml_document_t, index int)
-//{
-//    assert(document) // Non-NULL document object is expected.
-//
-//    if (index > 0 && document.nodes.start + index <= document.nodes.top) {
-//        return document.nodes.start + index - 1
-//    }
-//    return NULL
-//}
-//
-///**
-// * Get the root object.
-// */
-//
-//YAML_DECLARE(yaml_node_t *)
-//yaml_document_get_root_node(document *yaml_document_t)
-//{
-//    assert(document) // Non-NULL document object is expected.
-//
-//    if (document.nodes.top != document.nodes.start) {
-//        return document.nodes.start
-//    }
-//    return NULL
-//}
-//
-///*
-// * Add a scalar node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_scalar(document *yaml_document_t,
-//        tag *yaml_char_t, value *yaml_char_t, length int,
-//        style yaml_scalar_style_t)
-//{
-//    struct {
-//        error yaml_error_type_t
-//    } context
-//    mark yaml_mark_t = { 0, 0, 0 }
-//    tag_copy *yaml_char_t = NULL
-//    value_copy *yaml_char_t = NULL
-//    node yaml_node_t
-//
-//    assert(document) // Non-NULL document object is expected.
-//    assert(value) // Non-NULL value is expected.
-//
-//    if (!tag) {
-//        tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
-//    }
-//
-//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-//    tag_copy = yaml_strdup(tag)
-//    if (!tag_copy) goto error
-//
-//    if (length < 0) {
-//        length = strlen((char *)value)
-//    }
-//
-//    if (!yaml_check_utf8(value, length)) goto error
-//    value_copy = yaml_malloc(length+1)
-//    if (!value_copy) goto error
-//    memcpy(value_copy, value, length)
-//    value_copy[length] = '\0'
-//
-//    SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
-//    if (!PUSH(&context, document.nodes, node)) goto error
-//
-//    return document.nodes.top - document.nodes.start
-//
-//error:
-//    yaml_free(tag_copy)
-//    yaml_free(value_copy)
-//
-//    return 0
-//}
-//
-///*
-// * Add a sequence node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_sequence(document *yaml_document_t,
-//        tag *yaml_char_t, style yaml_sequence_style_t)
-//{
-//    struct {
-//        error yaml_error_type_t
-//    } context
-//    mark yaml_mark_t = { 0, 0, 0 }
-//    tag_copy *yaml_char_t = NULL
-//    struct {
-//        start *yaml_node_item_t
-//        end *yaml_node_item_t
-//        top *yaml_node_item_t
-//    } items = { NULL, NULL, NULL }
-//    node yaml_node_t
-//
-//    assert(document) // Non-NULL document object is expected.
-//
-//    if (!tag) {
-//        tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
-//    }
-//
-//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-//    tag_copy = yaml_strdup(tag)
-//    if (!tag_copy) goto error
-//
-//    if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
-//
-//    SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
-//            style, mark, mark)
-//    if (!PUSH(&context, document.nodes, node)) goto error
-//
-//    return document.nodes.top - document.nodes.start
-//
-//error:
-//    STACK_DEL(&context, items)
-//    yaml_free(tag_copy)
-//
-//    return 0
-//}
-//
-///*
-// * Add a mapping node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_mapping(document *yaml_document_t,
-//        tag *yaml_char_t, style yaml_mapping_style_t)
-//{
-//    struct {
-//        error yaml_error_type_t
-//    } context
-//    mark yaml_mark_t = { 0, 0, 0 }
-//    tag_copy *yaml_char_t = NULL
-//    struct {
-//        start *yaml_node_pair_t
-//        end *yaml_node_pair_t
-//        top *yaml_node_pair_t
-//    } pairs = { NULL, NULL, NULL }
-//    node yaml_node_t
-//
-//    assert(document) // Non-NULL document object is expected.
-//
-//    if (!tag) {
-//        tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
-//    }
-//
-//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-//    tag_copy = yaml_strdup(tag)
-//    if (!tag_copy) goto error
-//
-//    if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
-//
-//    MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
-//            style, mark, mark)
-//    if (!PUSH(&context, document.nodes, node)) goto error
-//
-//    return document.nodes.top - document.nodes.start
-//
-//error:
-//    STACK_DEL(&context, pairs)
-//    yaml_free(tag_copy)
-//
-//    return 0
-//}
-//
-///*
-// * Append an item to a sequence node.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_append_sequence_item(document *yaml_document_t,
-//        sequence int, item int)
-//{
-//    struct {
-//        error yaml_error_type_t
-//    } context
-//
-//    assert(document) // Non-NULL document is required.
-//    assert(sequence > 0
-//            && document.nodes.start + sequence <= document.nodes.top)
-//                            // Valid sequence id is required.
-//    assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
-//                            // A sequence node is required.
-//    assert(item > 0 && document.nodes.start + item <= document.nodes.top)
-//                            // Valid item id is required.
-//
-//    if (!PUSH(&context,
-//                document.nodes.start[sequence-1].data.sequence.items, item))
-//        return 0
-//
-//    return 1
-//}
-//
-///*
-// * Append a pair of a key and a value to a mapping node.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_append_mapping_pair(document *yaml_document_t,
-//        mapping int, key int, value int)
-//{
-//    struct {
-//        error yaml_error_type_t
-//    } context
-//
-//    pair yaml_node_pair_t
-//
-//    assert(document) // Non-NULL document is required.
-//    assert(mapping > 0
-//            && document.nodes.start + mapping <= document.nodes.top)
-//                            // Valid mapping id is required.
-//    assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
-//                            // A mapping node is required.
-//    assert(key > 0 && document.nodes.start + key <= document.nodes.top)
-//                            // Valid key id is required.
-//    assert(value > 0 && document.nodes.start + value <= document.nodes.top)
-//                            // Valid value id is required.
-//
-//    pair.key = key
-//    pair.value = value
-//
-//    if (!PUSH(&context,
-//                document.nodes.start[mapping-1].data.mapping.pairs, pair))
-//        return 0
-//
-//    return 1
-//}
-//
-//
tools/review-tool/vendor/gopkg.in/yaml.v3/decode.go
@@ -1,1000 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package yaml
-
-import (
-	"encoding"
-	"encoding/base64"
-	"fmt"
-	"io"
-	"math"
-	"reflect"
-	"strconv"
-	"time"
-)
-
-// ----------------------------------------------------------------------------
-// Parser, produces a node tree out of a libyaml event stream.
-
-type parser struct {
-	parser   yaml_parser_t
-	event    yaml_event_t
-	doc      *Node
-	anchors  map[string]*Node
-	doneInit bool
-	textless bool
-}
-
-func newParser(b []byte) *parser {
-	p := parser{}
-	if !yaml_parser_initialize(&p.parser) {
-		panic("failed to initialize YAML emitter")
-	}
-	if len(b) == 0 {
-		b = []byte{'\n'}
-	}
-	yaml_parser_set_input_string(&p.parser, b)
-	return &p
-}
-
-func newParserFromReader(r io.Reader) *parser {
-	p := parser{}
-	if !yaml_parser_initialize(&p.parser) {
-		panic("failed to initialize YAML emitter")
-	}
-	yaml_parser_set_input_reader(&p.parser, r)
-	return &p
-}
-
-func (p *parser) init() {
-	if p.doneInit {
-		return
-	}
-	p.anchors = make(map[string]*Node)
-	p.expect(yaml_STREAM_START_EVENT)
-	p.doneInit = true
-}
-
-func (p *parser) destroy() {
-	if p.event.typ != yaml_NO_EVENT {
-		yaml_event_delete(&p.event)
-	}
-	yaml_parser_delete(&p.parser)
-}
-
-// expect consumes an event from the event stream and
-// checks that it's of the expected type.
-func (p *parser) expect(e yaml_event_type_t) {
-	if p.event.typ == yaml_NO_EVENT {
-		if !yaml_parser_parse(&p.parser, &p.event) {
-			p.fail()
-		}
-	}
-	if p.event.typ == yaml_STREAM_END_EVENT {
-		failf("attempted to go past the end of stream; corrupted value?")
-	}
-	if p.event.typ != e {
-		p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
-		p.fail()
-	}
-	yaml_event_delete(&p.event)
-	p.event.typ = yaml_NO_EVENT
-}
-
-// peek peeks at the next event in the event stream,
-// puts the results into p.event and returns the event type.
-func (p *parser) peek() yaml_event_type_t {
-	if p.event.typ != yaml_NO_EVENT {
-		return p.event.typ
-	}
-	// It's curious choice from the underlying API to generally return a
-	// positive result on success, but on this case return true in an error
-	// scenario. This was the source of bugs in the past (issue #666).
-	if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {
-		p.fail()
-	}
-	return p.event.typ
-}
-
-func (p *parser) fail() {
-	var where string
-	var line int
-	if p.parser.context_mark.line != 0 {
-		line = p.parser.context_mark.line
-		// Scanner errors don't iterate line before returning error
-		if p.parser.error == yaml_SCANNER_ERROR {
-			line++
-		}
-	} else if p.parser.problem_mark.line != 0 {
-		line = p.parser.problem_mark.line
-		// Scanner errors don't iterate line before returning error
-		if p.parser.error == yaml_SCANNER_ERROR {
-			line++
-		}
-	}
-	if line != 0 {
-		where = "line " + strconv.Itoa(line) + ": "
-	}
-	var msg string
-	if len(p.parser.problem) > 0 {
-		msg = p.parser.problem
-	} else {
-		msg = "unknown problem parsing YAML content"
-	}
-	failf("%s%s", where, msg)
-}
-
-func (p *parser) anchor(n *Node, anchor []byte) {
-	if anchor != nil {
-		n.Anchor = string(anchor)
-		p.anchors[n.Anchor] = n
-	}
-}
-
-func (p *parser) parse() *Node {
-	p.init()
-	switch p.peek() {
-	case yaml_SCALAR_EVENT:
-		return p.scalar()
-	case yaml_ALIAS_EVENT:
-		return p.alias()
-	case yaml_MAPPING_START_EVENT:
-		return p.mapping()
-	case yaml_SEQUENCE_START_EVENT:
-		return p.sequence()
-	case yaml_DOCUMENT_START_EVENT:
-		return p.document()
-	case yaml_STREAM_END_EVENT:
-		// Happens when attempting to decode an empty buffer.
-		return nil
-	case yaml_TAIL_COMMENT_EVENT:
-		panic("internal error: unexpected tail comment event (please report)")
-	default:
-		panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())
-	}
-}
-
-func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
-	var style Style
-	if tag != "" && tag != "!" {
-		tag = shortTag(tag)
-		style = TaggedStyle
-	} else if defaultTag != "" {
-		tag = defaultTag
-	} else if kind == ScalarNode {
-		tag, _ = resolve("", value)
-	}
-	n := &Node{
-		Kind:  kind,
-		Tag:   tag,
-		Value: value,
-		Style: style,
-	}
-	if !p.textless {
-		n.Line = p.event.start_mark.line + 1
-		n.Column = p.event.start_mark.column + 1
-		n.HeadComment = string(p.event.head_comment)
-		n.LineComment = string(p.event.line_comment)
-		n.FootComment = string(p.event.foot_comment)
-	}
-	return n
-}
-
-func (p *parser) parseChild(parent *Node) *Node {
-	child := p.parse()
-	parent.Content = append(parent.Content, child)
-	return child
-}
-
-func (p *parser) document() *Node {
-	n := p.node(DocumentNode, "", "", "")
-	p.doc = n
-	p.expect(yaml_DOCUMENT_START_EVENT)
-	p.parseChild(n)
-	if p.peek() == yaml_DOCUMENT_END_EVENT {
-		n.FootComment = string(p.event.foot_comment)
-	}
-	p.expect(yaml_DOCUMENT_END_EVENT)
-	return n
-}
-
-func (p *parser) alias() *Node {
-	n := p.node(AliasNode, "", "", string(p.event.anchor))
-	n.Alias = p.anchors[n.Value]
-	if n.Alias == nil {
-		failf("unknown anchor '%s' referenced", n.Value)
-	}
-	p.expect(yaml_ALIAS_EVENT)
-	return n
-}
-
-func (p *parser) scalar() *Node {
-	var parsedStyle = p.event.scalar_style()
-	var nodeStyle Style
-	switch {
-	case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
-		nodeStyle = DoubleQuotedStyle
-	case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
-		nodeStyle = SingleQuotedStyle
-	case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:
-		nodeStyle = LiteralStyle
-	case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:
-		nodeStyle = FoldedStyle
-	}
-	var nodeValue = string(p.event.value)
-	var nodeTag = string(p.event.tag)
-	var defaultTag string
-	if nodeStyle == 0 {
-		if nodeValue == "<<" {
-			defaultTag = mergeTag
-		}
-	} else {
-		defaultTag = strTag
-	}
-	n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)
-	n.Style |= nodeStyle
-	p.anchor(n, p.event.anchor)
-	p.expect(yaml_SCALAR_EVENT)
-	return n
-}
-
-func (p *parser) sequence() *Node {
-	n := p.node(SequenceNode, seqTag, string(p.event.tag), "")
-	if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
-		n.Style |= FlowStyle
-	}
-	p.anchor(n, p.event.anchor)
-	p.expect(yaml_SEQUENCE_START_EVENT)
-	for p.peek() != yaml_SEQUENCE_END_EVENT {
-		p.parseChild(n)
-	}
-	n.LineComment = string(p.event.line_comment)
-	n.FootComment = string(p.event.foot_comment)
-	p.expect(yaml_SEQUENCE_END_EVENT)
-	return n
-}
-
-func (p *parser) mapping() *Node {
-	n := p.node(MappingNode, mapTag, string(p.event.tag), "")
-	block := true
-	if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
-		block = false
-		n.Style |= FlowStyle
-	}
-	p.anchor(n, p.event.anchor)
-	p.expect(yaml_MAPPING_START_EVENT)
-	for p.peek() != yaml_MAPPING_END_EVENT {
-		k := p.parseChild(n)
-		if block && k.FootComment != "" {
-			// Must be a foot comment for the prior value when being dedented.
-			if len(n.Content) > 2 {
-				n.Content[len(n.Content)-3].FootComment = k.FootComment
-				k.FootComment = ""
-			}
-		}
-		v := p.parseChild(n)
-		if k.FootComment == "" && v.FootComment != "" {
-			k.FootComment = v.FootComment
-			v.FootComment = ""
-		}
-		if p.peek() == yaml_TAIL_COMMENT_EVENT {
-			if k.FootComment == "" {
-				k.FootComment = string(p.event.foot_comment)
-			}
-			p.expect(yaml_TAIL_COMMENT_EVENT)
-		}
-	}
-	n.LineComment = string(p.event.line_comment)
-	n.FootComment = string(p.event.foot_comment)
-	if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {
-		n.Content[len(n.Content)-2].FootComment = n.FootComment
-		n.FootComment = ""
-	}
-	p.expect(yaml_MAPPING_END_EVENT)
-	return n
-}
-
-// ----------------------------------------------------------------------------
-// Decoder, unmarshals a node into a provided value.
-
-type decoder struct {
-	doc     *Node
-	aliases map[*Node]bool
-	terrors []string
-
-	stringMapType  reflect.Type
-	generalMapType reflect.Type
-
-	knownFields bool
-	uniqueKeys  bool
-	decodeCount int
-	aliasCount  int
-	aliasDepth  int
-
-	mergedFields map[interface{}]bool
-}
-
-var (
-	nodeType       = reflect.TypeOf(Node{})
-	durationType   = reflect.TypeOf(time.Duration(0))
-	stringMapType  = reflect.TypeOf(map[string]interface{}{})
-	generalMapType = reflect.TypeOf(map[interface{}]interface{}{})
-	ifaceType      = generalMapType.Elem()
-	timeType       = reflect.TypeOf(time.Time{})
-	ptrTimeType    = reflect.TypeOf(&time.Time{})
-)
-
-func newDecoder() *decoder {
-	d := &decoder{
-		stringMapType:  stringMapType,
-		generalMapType: generalMapType,
-		uniqueKeys:     true,
-	}
-	d.aliases = make(map[*Node]bool)
-	return d
-}
-
-func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
-	if n.Tag != "" {
-		tag = n.Tag
-	}
-	value := n.Value
-	if tag != seqTag && tag != mapTag {
-		if len(value) > 10 {
-			value = " `" + value[:7] + "...`"
-		} else {
-			value = " `" + value + "`"
-		}
-	}
-	d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))
-}
-
-func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
-	err := u.UnmarshalYAML(n)
-	if e, ok := err.(*TypeError); ok {
-		d.terrors = append(d.terrors, e.Errors...)
-		return false
-	}
-	if err != nil {
-		fail(err)
-	}
-	return true
-}
-
-func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {
-	terrlen := len(d.terrors)
-	err := u.UnmarshalYAML(func(v interface{}) (err error) {
-		defer handleErr(&err)
-		d.unmarshal(n, reflect.ValueOf(v))
-		if len(d.terrors) > terrlen {
-			issues := d.terrors[terrlen:]
-			d.terrors = d.terrors[:terrlen]
-			return &TypeError{issues}
-		}
-		return nil
-	})
-	if e, ok := err.(*TypeError); ok {
-		d.terrors = append(d.terrors, e.Errors...)
-		return false
-	}
-	if err != nil {
-		fail(err)
-	}
-	return true
-}
-
-// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
-// if a value is found to implement it.
-// It returns the initialized and dereferenced out value, whether
-// unmarshalling was already done by UnmarshalYAML, and if so whether
-// its types unmarshalled appropriately.
-//
-// If n holds a null value, prepare returns before doing anything.
-func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
-	if n.ShortTag() == nullTag {
-		return out, false, false
-	}
-	again := true
-	for again {
-		again = false
-		if out.Kind() == reflect.Ptr {
-			if out.IsNil() {
-				out.Set(reflect.New(out.Type().Elem()))
-			}
-			out = out.Elem()
-			again = true
-		}
-		if out.CanAddr() {
-			outi := out.Addr().Interface()
-			if u, ok := outi.(Unmarshaler); ok {
-				good = d.callUnmarshaler(n, u)
-				return out, true, good
-			}
-			if u, ok := outi.(obsoleteUnmarshaler); ok {
-				good = d.callObsoleteUnmarshaler(n, u)
-				return out, true, good
-			}
-		}
-	}
-	return out, false, false
-}
-
-func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {
-	if n.ShortTag() == nullTag {
-		return reflect.Value{}
-	}
-	for _, num := range index {
-		for {
-			if v.Kind() == reflect.Ptr {
-				if v.IsNil() {
-					v.Set(reflect.New(v.Type().Elem()))
-				}
-				v = v.Elem()
-				continue
-			}
-			break
-		}
-		v = v.Field(num)
-	}
-	return v
-}
-
-const (
-	// 400,000 decode operations is ~500kb of dense object declarations, or
-	// ~5kb of dense object declarations with 10000% alias expansion
-	alias_ratio_range_low = 400000
-
-	// 4,000,000 decode operations is ~5MB of dense object declarations, or
-	// ~4.5MB of dense object declarations with 10% alias expansion
-	alias_ratio_range_high = 4000000
-
-	// alias_ratio_range is the range over which we scale allowed alias ratios
-	alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
-)
-
-func allowedAliasRatio(decodeCount int) float64 {
-	switch {
-	case decodeCount <= alias_ratio_range_low:
-		// allow 99% to come from alias expansion for small-to-medium documents
-		return 0.99
-	case decodeCount >= alias_ratio_range_high:
-		// allow 10% to come from alias expansion for very large documents
-		return 0.10
-	default:
-		// scale smoothly from 99% down to 10% over the range.
-		// this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
-		// 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
-		return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
-	}
-}
-
-func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
-	d.decodeCount++
-	if d.aliasDepth > 0 {
-		d.aliasCount++
-	}
-	if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
-		failf("document contains excessive aliasing")
-	}
-	if out.Type() == nodeType {
-		out.Set(reflect.ValueOf(n).Elem())
-		return true
-	}
-	switch n.Kind {
-	case DocumentNode:
-		return d.document(n, out)
-	case AliasNode:
-		return d.alias(n, out)
-	}
-	out, unmarshaled, good := d.prepare(n, out)
-	if unmarshaled {
-		return good
-	}
-	switch n.Kind {
-	case ScalarNode:
-		good = d.scalar(n, out)
-	case MappingNode:
-		good = d.mapping(n, out)
-	case SequenceNode:
-		good = d.sequence(n, out)
-	case 0:
-		if n.IsZero() {
-			return d.null(out)
-		}
-		fallthrough
-	default:
-		failf("cannot decode node with unknown kind %d", n.Kind)
-	}
-	return good
-}
-
-func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
-	if len(n.Content) == 1 {
-		d.doc = n
-		d.unmarshal(n.Content[0], out)
-		return true
-	}
-	return false
-}
-
-func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
-	if d.aliases[n] {
-		// TODO this could actually be allowed in some circumstances.
-		failf("anchor '%s' value contains itself", n.Value)
-	}
-	d.aliases[n] = true
-	d.aliasDepth++
-	good = d.unmarshal(n.Alias, out)
-	d.aliasDepth--
-	delete(d.aliases, n)
-	return good
-}
-
-var zeroValue reflect.Value
-
-func resetMap(out reflect.Value) {
-	for _, k := range out.MapKeys() {
-		out.SetMapIndex(k, zeroValue)
-	}
-}
-
-func (d *decoder) null(out reflect.Value) bool {
-	if out.CanAddr() {
-		switch out.Kind() {
-		case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
-			out.Set(reflect.Zero(out.Type()))
-			return true
-		}
-	}
-	return false
-}
-
-func (d *decoder) scalar(n *Node, out reflect.Value) bool {
-	var tag string
-	var resolved interface{}
-	if n.indicatedString() {
-		tag = strTag
-		resolved = n.Value
-	} else {
-		tag, resolved = resolve(n.Tag, n.Value)
-		if tag == binaryTag {
-			data, err := base64.StdEncoding.DecodeString(resolved.(string))
-			if err != nil {
-				failf("!!binary value contains invalid base64 data")
-			}
-			resolved = string(data)
-		}
-	}
-	if resolved == nil {
-		return d.null(out)
-	}
-	if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
-		// We've resolved to exactly the type we want, so use that.
-		out.Set(resolvedv)
-		return true
-	}
-	// Perhaps we can use the value as a TextUnmarshaler to
-	// set its value.
-	if out.CanAddr() {
-		u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
-		if ok {
-			var text []byte
-			if tag == binaryTag {
-				text = []byte(resolved.(string))
-			} else {
-				// We let any value be unmarshaled into TextUnmarshaler.
-				// That might be more lax than we'd like, but the
-				// TextUnmarshaler itself should bowl out any dubious values.
-				text = []byte(n.Value)
-			}
-			err := u.UnmarshalText(text)
-			if err != nil {
-				fail(err)
-			}
-			return true
-		}
-	}
-	switch out.Kind() {
-	case reflect.String:
-		if tag == binaryTag {
-			out.SetString(resolved.(string))
-			return true
-		}
-		out.SetString(n.Value)
-		return true
-	case reflect.Interface:
-		out.Set(reflect.ValueOf(resolved))
-		return true
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		// This used to work in v2, but it's very unfriendly.
-		isDuration := out.Type() == durationType
-
-		switch resolved := resolved.(type) {
-		case int:
-			if !isDuration && !out.OverflowInt(int64(resolved)) {
-				out.SetInt(int64(resolved))
-				return true
-			}
-		case int64:
-			if !isDuration && !out.OverflowInt(resolved) {
-				out.SetInt(resolved)
-				return true
-			}
-		case uint64:
-			if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
-				out.SetInt(int64(resolved))
-				return true
-			}
-		case float64:
-			if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
-				out.SetInt(int64(resolved))
-				return true
-			}
-		case string:
-			if out.Type() == durationType {
-				d, err := time.ParseDuration(resolved)
-				if err == nil {
-					out.SetInt(int64(d))
-					return true
-				}
-			}
-		}
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		switch resolved := resolved.(type) {
-		case int:
-			if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
-				out.SetUint(uint64(resolved))
-				return true
-			}
-		case int64:
-			if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
-				out.SetUint(uint64(resolved))
-				return true
-			}
-		case uint64:
-			if !out.OverflowUint(uint64(resolved)) {
-				out.SetUint(uint64(resolved))
-				return true
-			}
-		case float64:
-			if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
-				out.SetUint(uint64(resolved))
-				return true
-			}
-		}
-	case reflect.Bool:
-		switch resolved := resolved.(type) {
-		case bool:
-			out.SetBool(resolved)
-			return true
-		case string:
-			// This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).
-			// It only works if explicitly attempting to unmarshal into a typed bool value.
-			switch resolved {
-			case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
-				out.SetBool(true)
-				return true
-			case "n", "N", "no", "No", "NO", "off", "Off", "OFF":
-				out.SetBool(false)
-				return true
-			}
-		}
-	case reflect.Float32, reflect.Float64:
-		switch resolved := resolved.(type) {
-		case int:
-			out.SetFloat(float64(resolved))
-			return true
-		case int64:
-			out.SetFloat(float64(resolved))
-			return true
-		case uint64:
-			out.SetFloat(float64(resolved))
-			return true
-		case float64:
-			out.SetFloat(resolved)
-			return true
-		}
-	case reflect.Struct:
-		if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
-			out.Set(resolvedv)
-			return true
-		}
-	case reflect.Ptr:
-		panic("yaml internal error: please report the issue")
-	}
-	d.terror(n, tag, out)
-	return false
-}
-
-func settableValueOf(i interface{}) reflect.Value {
-	v := reflect.ValueOf(i)
-	sv := reflect.New(v.Type()).Elem()
-	sv.Set(v)
-	return sv
-}
-
-func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
-	l := len(n.Content)
-
-	var iface reflect.Value
-	switch out.Kind() {
-	case reflect.Slice:
-		out.Set(reflect.MakeSlice(out.Type(), l, l))
-	case reflect.Array:
-		if l != out.Len() {
-			failf("invalid array: want %d elements but got %d", out.Len(), l)
-		}
-	case reflect.Interface:
-		// No type hints. Will have to use a generic sequence.
-		iface = out
-		out = settableValueOf(make([]interface{}, l))
-	default:
-		d.terror(n, seqTag, out)
-		return false
-	}
-	et := out.Type().Elem()
-
-	j := 0
-	for i := 0; i < l; i++ {
-		e := reflect.New(et).Elem()
-		if ok := d.unmarshal(n.Content[i], e); ok {
-			out.Index(j).Set(e)
-			j++
-		}
-	}
-	if out.Kind() != reflect.Array {
-		out.Set(out.Slice(0, j))
-	}
-	if iface.IsValid() {
-		iface.Set(out)
-	}
-	return true
-}
-
-func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
-	l := len(n.Content)
-	if d.uniqueKeys {
-		nerrs := len(d.terrors)
-		for i := 0; i < l; i += 2 {
-			ni := n.Content[i]
-			for j := i + 2; j < l; j += 2 {
-				nj := n.Content[j]
-				if ni.Kind == nj.Kind && ni.Value == nj.Value {
-					d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
-				}
-			}
-		}
-		if len(d.terrors) > nerrs {
-			return false
-		}
-	}
-	switch out.Kind() {
-	case reflect.Struct:
-		return d.mappingStruct(n, out)
-	case reflect.Map:
-		// okay
-	case reflect.Interface:
-		iface := out
-		if isStringMap(n) {
-			out = reflect.MakeMap(d.stringMapType)
-		} else {
-			out = reflect.MakeMap(d.generalMapType)
-		}
-		iface.Set(out)
-	default:
-		d.terror(n, mapTag, out)
-		return false
-	}
-
-	outt := out.Type()
-	kt := outt.Key()
-	et := outt.Elem()
-
-	stringMapType := d.stringMapType
-	generalMapType := d.generalMapType
-	if outt.Elem() == ifaceType {
-		if outt.Key().Kind() == reflect.String {
-			d.stringMapType = outt
-		} else if outt.Key() == ifaceType {
-			d.generalMapType = outt
-		}
-	}
-
-	mergedFields := d.mergedFields
-	d.mergedFields = nil
-
-	var mergeNode *Node
-
-	mapIsNew := false
-	if out.IsNil() {
-		out.Set(reflect.MakeMap(outt))
-		mapIsNew = true
-	}
-	for i := 0; i < l; i += 2 {
-		if isMerge(n.Content[i]) {
-			mergeNode = n.Content[i+1]
-			continue
-		}
-		k := reflect.New(kt).Elem()
-		if d.unmarshal(n.Content[i], k) {
-			if mergedFields != nil {
-				ki := k.Interface()
-				if mergedFields[ki] {
-					continue
-				}
-				mergedFields[ki] = true
-			}
-			kkind := k.Kind()
-			if kkind == reflect.Interface {
-				kkind = k.Elem().Kind()
-			}
-			if kkind == reflect.Map || kkind == reflect.Slice {
-				failf("invalid map key: %#v", k.Interface())
-			}
-			e := reflect.New(et).Elem()
-			if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) {
-				out.SetMapIndex(k, e)
-			}
-		}
-	}
-
-	d.mergedFields = mergedFields
-	if mergeNode != nil {
-		d.merge(n, mergeNode, out)
-	}
-
-	d.stringMapType = stringMapType
-	d.generalMapType = generalMapType
-	return true
-}
-
-func isStringMap(n *Node) bool {
-	if n.Kind != MappingNode {
-		return false
-	}
-	l := len(n.Content)
-	for i := 0; i < l; i += 2 {
-		shortTag := n.Content[i].ShortTag()
-		if shortTag != strTag && shortTag != mergeTag {
-			return false
-		}
-	}
-	return true
-}
-
-func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
-	sinfo, err := getStructInfo(out.Type())
-	if err != nil {
-		panic(err)
-	}
-
-	var inlineMap reflect.Value
-	var elemType reflect.Type
-	if sinfo.InlineMap != -1 {
-		inlineMap = out.Field(sinfo.InlineMap)
-		elemType = inlineMap.Type().Elem()
-	}
-
-	for _, index := range sinfo.InlineUnmarshalers {
-		field := d.fieldByIndex(n, out, index)
-		d.prepare(n, field)
-	}
-
-	mergedFields := d.mergedFields
-	d.mergedFields = nil
-	var mergeNode *Node
-	var doneFields []bool
-	if d.uniqueKeys {
-		doneFields = make([]bool, len(sinfo.FieldsList))
-	}
-	name := settableValueOf("")
-	l := len(n.Content)
-	for i := 0; i < l; i += 2 {
-		ni := n.Content[i]
-		if isMerge(ni) {
-			mergeNode = n.Content[i+1]
-			continue
-		}
-		if !d.unmarshal(ni, name) {
-			continue
-		}
-		sname := name.String()
-		if mergedFields != nil {
-			if mergedFields[sname] {
-				continue
-			}
-			mergedFields[sname] = true
-		}
-		if info, ok := sinfo.FieldsMap[sname]; ok {
-			if d.uniqueKeys {
-				if doneFields[info.Id] {
-					d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
-					continue
-				}
-				doneFields[info.Id] = true
-			}
-			var field reflect.Value
-			if info.Inline == nil {
-				field = out.Field(info.Num)
-			} else {
-				field = d.fieldByIndex(n, out, info.Inline)
-			}
-			d.unmarshal(n.Content[i+1], field)
-		} else if sinfo.InlineMap != -1 {
-			if inlineMap.IsNil() {
-				inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
-			}
-			value := reflect.New(elemType).Elem()
-			d.unmarshal(n.Content[i+1], value)
-			inlineMap.SetMapIndex(name, value)
-		} else if d.knownFields {
-			d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
-		}
-	}
-
-	d.mergedFields = mergedFields
-	if mergeNode != nil {
-		d.merge(n, mergeNode, out)
-	}
-	return true
-}
-
-func failWantMap() {
-	failf("map merge requires map or sequence of maps as the value")
-}
-
-func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {
-	mergedFields := d.mergedFields
-	if mergedFields == nil {
-		d.mergedFields = make(map[interface{}]bool)
-		for i := 0; i < len(parent.Content); i += 2 {
-			k := reflect.New(ifaceType).Elem()
-			if d.unmarshal(parent.Content[i], k) {
-				d.mergedFields[k.Interface()] = true
-			}
-		}
-	}
-
-	switch merge.Kind {
-	case MappingNode:
-		d.unmarshal(merge, out)
-	case AliasNode:
-		if merge.Alias != nil && merge.Alias.Kind != MappingNode {
-			failWantMap()
-		}
-		d.unmarshal(merge, out)
-	case SequenceNode:
-		for i := 0; i < len(merge.Content); i++ {
-			ni := merge.Content[i]
-			if ni.Kind == AliasNode {
-				if ni.Alias != nil && ni.Alias.Kind != MappingNode {
-					failWantMap()
-				}
-			} else if ni.Kind != MappingNode {
-				failWantMap()
-			}
-			d.unmarshal(ni, out)
-		}
-	default:
-		failWantMap()
-	}
-
-	d.mergedFields = mergedFields
-}
-
-func isMerge(n *Node) bool {
-	return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/emitterc.go
@@ -1,2019 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
-	"bytes"
-	"fmt"
-)
-
-// Flush the buffer if needed.
-func flush(emitter *yaml_emitter_t) bool {
-	if emitter.buffer_pos+5 >= len(emitter.buffer) {
-		return yaml_emitter_flush(emitter)
-	}
-	return true
-}
-
-// Put a character to the output buffer.
-func put(emitter *yaml_emitter_t, value byte) bool {
-	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
-		return false
-	}
-	emitter.buffer[emitter.buffer_pos] = value
-	emitter.buffer_pos++
-	emitter.column++
-	return true
-}
-
-// Put a line break to the output buffer.
-func put_break(emitter *yaml_emitter_t) bool {
-	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
-		return false
-	}
-	switch emitter.line_break {
-	case yaml_CR_BREAK:
-		emitter.buffer[emitter.buffer_pos] = '\r'
-		emitter.buffer_pos += 1
-	case yaml_LN_BREAK:
-		emitter.buffer[emitter.buffer_pos] = '\n'
-		emitter.buffer_pos += 1
-	case yaml_CRLN_BREAK:
-		emitter.buffer[emitter.buffer_pos+0] = '\r'
-		emitter.buffer[emitter.buffer_pos+1] = '\n'
-		emitter.buffer_pos += 2
-	default:
-		panic("unknown line break setting")
-	}
-	if emitter.column == 0 {
-		emitter.space_above = true
-	}
-	emitter.column = 0
-	emitter.line++
-	// [Go] Do this here and below and drop from everywhere else (see commented lines).
-	emitter.indention = true
-	return true
-}
-
-// Copy a character from a string into buffer.
-func write(emitter *yaml_emitter_t, s []byte, i *int) bool {
-	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
-		return false
-	}
-	p := emitter.buffer_pos
-	w := width(s[*i])
-	switch w {
-	case 4:
-		emitter.buffer[p+3] = s[*i+3]
-		fallthrough
-	case 3:
-		emitter.buffer[p+2] = s[*i+2]
-		fallthrough
-	case 2:
-		emitter.buffer[p+1] = s[*i+1]
-		fallthrough
-	case 1:
-		emitter.buffer[p+0] = s[*i+0]
-	default:
-		panic("unknown character width")
-	}
-	emitter.column++
-	emitter.buffer_pos += w
-	*i += w
-	return true
-}
-
-// Write a whole string into buffer.
-func write_all(emitter *yaml_emitter_t, s []byte) bool {
-	for i := 0; i < len(s); {
-		if !write(emitter, s, &i) {
-			return false
-		}
-	}
-	return true
-}
-
-// Copy a line break character from a string into buffer.
-func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool {
-	if s[*i] == '\n' {
-		if !put_break(emitter) {
-			return false
-		}
-		*i++
-	} else {
-		if !write(emitter, s, i) {
-			return false
-		}
-		if emitter.column == 0 {
-			emitter.space_above = true
-		}
-		emitter.column = 0
-		emitter.line++
-		// [Go] Do this here and above and drop from everywhere else (see commented lines).
-		emitter.indention = true
-	}
-	return true
-}
-
-// Set an emitter error and return false.
-func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool {
-	emitter.error = yaml_EMITTER_ERROR
-	emitter.problem = problem
-	return false
-}
-
-// Emit an event.
-func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	emitter.events = append(emitter.events, *event)
-	for !yaml_emitter_need_more_events(emitter) {
-		event := &emitter.events[emitter.events_head]
-		if !yaml_emitter_analyze_event(emitter, event) {
-			return false
-		}
-		if !yaml_emitter_state_machine(emitter, event) {
-			return false
-		}
-		yaml_event_delete(event)
-		emitter.events_head++
-	}
-	return true
-}
-
-// Check if we need to accumulate more events before emitting.
-//
-// We accumulate extra
-//   - 1 event for DOCUMENT-START
-//   - 2 events for SEQUENCE-START
-//   - 3 events for MAPPING-START
-func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
-	if emitter.events_head == len(emitter.events) {
-		return true
-	}
-	var accumulate int
-	switch emitter.events[emitter.events_head].typ {
-	case yaml_DOCUMENT_START_EVENT:
-		accumulate = 1
-		break
-	case yaml_SEQUENCE_START_EVENT:
-		accumulate = 2
-		break
-	case yaml_MAPPING_START_EVENT:
-		accumulate = 3
-		break
-	default:
-		return false
-	}
-	if len(emitter.events)-emitter.events_head > accumulate {
-		return false
-	}
-	var level int
-	for i := emitter.events_head; i < len(emitter.events); i++ {
-		switch emitter.events[i].typ {
-		case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT:
-			level++
-		case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT:
-			level--
-		}
-		if level == 0 {
-			return false
-		}
-	}
-	return true
-}
-
-// Append a directive to the directives stack.
-func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool {
-	for i := 0; i < len(emitter.tag_directives); i++ {
-		if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
-			if allow_duplicates {
-				return true
-			}
-			return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive")
-		}
-	}
-
-	// [Go] Do we actually need to copy this given garbage collection
-	// and the lack of deallocating destructors?
-	tag_copy := yaml_tag_directive_t{
-		handle: make([]byte, len(value.handle)),
-		prefix: make([]byte, len(value.prefix)),
-	}
-	copy(tag_copy.handle, value.handle)
-	copy(tag_copy.prefix, value.prefix)
-	emitter.tag_directives = append(emitter.tag_directives, tag_copy)
-	return true
-}
-
-// Increase the indentation level.
-func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool {
-	emitter.indents = append(emitter.indents, emitter.indent)
-	if emitter.indent < 0 {
-		if flow {
-			emitter.indent = emitter.best_indent
-		} else {
-			emitter.indent = 0
-		}
-	} else if !indentless {
-		// [Go] This was changed so that indentations are more regular.
-		if emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE {
-			// The first indent inside a sequence will just skip the "- " indicator.
-			emitter.indent += 2
-		} else {
-			// Everything else aligns to the chosen indentation.
-			emitter.indent = emitter.best_indent * ((emitter.indent + emitter.best_indent) / emitter.best_indent)
-		}
-	}
-	return true
-}
-
-// State dispatcher.
-func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	switch emitter.state {
-	default:
-	case yaml_EMIT_STREAM_START_STATE:
-		return yaml_emitter_emit_stream_start(emitter, event)
-
-	case yaml_EMIT_FIRST_DOCUMENT_START_STATE:
-		return yaml_emitter_emit_document_start(emitter, event, true)
-
-	case yaml_EMIT_DOCUMENT_START_STATE:
-		return yaml_emitter_emit_document_start(emitter, event, false)
-
-	case yaml_EMIT_DOCUMENT_CONTENT_STATE:
-		return yaml_emitter_emit_document_content(emitter, event)
-
-	case yaml_EMIT_DOCUMENT_END_STATE:
-		return yaml_emitter_emit_document_end(emitter, event)
-
-	case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
-		return yaml_emitter_emit_flow_sequence_item(emitter, event, true, false)
-
-	case yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE:
-		return yaml_emitter_emit_flow_sequence_item(emitter, event, false, true)
-
-	case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE:
-		return yaml_emitter_emit_flow_sequence_item(emitter, event, false, false)
-
-	case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
-		return yaml_emitter_emit_flow_mapping_key(emitter, event, true, false)
-
-	case yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE:
-		return yaml_emitter_emit_flow_mapping_key(emitter, event, false, true)
-
-	case yaml_EMIT_FLOW_MAPPING_KEY_STATE:
-		return yaml_emitter_emit_flow_mapping_key(emitter, event, false, false)
-
-	case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
-		return yaml_emitter_emit_flow_mapping_value(emitter, event, true)
-
-	case yaml_EMIT_FLOW_MAPPING_VALUE_STATE:
-		return yaml_emitter_emit_flow_mapping_value(emitter, event, false)
-
-	case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
-		return yaml_emitter_emit_block_sequence_item(emitter, event, true)
-
-	case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
-		return yaml_emitter_emit_block_sequence_item(emitter, event, false)
-
-	case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
-		return yaml_emitter_emit_block_mapping_key(emitter, event, true)
-
-	case yaml_EMIT_BLOCK_MAPPING_KEY_STATE:
-		return yaml_emitter_emit_block_mapping_key(emitter, event, false)
-
-	case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
-		return yaml_emitter_emit_block_mapping_value(emitter, event, true)
-
-	case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE:
-		return yaml_emitter_emit_block_mapping_value(emitter, event, false)
-
-	case yaml_EMIT_END_STATE:
-		return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END")
-	}
-	panic("invalid emitter state")
-}
-
-// Expect STREAM-START.
-func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	if event.typ != yaml_STREAM_START_EVENT {
-		return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START")
-	}
-	if emitter.encoding == yaml_ANY_ENCODING {
-		emitter.encoding = event.encoding
-		if emitter.encoding == yaml_ANY_ENCODING {
-			emitter.encoding = yaml_UTF8_ENCODING
-		}
-	}
-	if emitter.best_indent < 2 || emitter.best_indent > 9 {
-		emitter.best_indent = 2
-	}
-	if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 {
-		emitter.best_width = 80
-	}
-	if emitter.best_width < 0 {
-		emitter.best_width = 1<<31 - 1
-	}
-	if emitter.line_break == yaml_ANY_BREAK {
-		emitter.line_break = yaml_LN_BREAK
-	}
-
-	emitter.indent = -1
-	emitter.line = 0
-	emitter.column = 0
-	emitter.whitespace = true
-	emitter.indention = true
-	emitter.space_above = true
-	emitter.foot_indent = -1
-
-	if emitter.encoding != yaml_UTF8_ENCODING {
-		if !yaml_emitter_write_bom(emitter) {
-			return false
-		}
-	}
-	emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE
-	return true
-}
-
-// Expect DOCUMENT-START or STREAM-END.
-func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
-
-	if event.typ == yaml_DOCUMENT_START_EVENT {
-
-		if event.version_directive != nil {
-			if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) {
-				return false
-			}
-		}
-
-		for i := 0; i < len(event.tag_directives); i++ {
-			tag_directive := &event.tag_directives[i]
-			if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) {
-				return false
-			}
-			if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) {
-				return false
-			}
-		}
-
-		for i := 0; i < len(default_tag_directives); i++ {
-			tag_directive := &default_tag_directives[i]
-			if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) {
-				return false
-			}
-		}
-
-		implicit := event.implicit
-		if !first || emitter.canonical {
-			implicit = false
-		}
-
-		if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) {
-			if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
-				return false
-			}
-			if !yaml_emitter_write_indent(emitter) {
-				return false
-			}
-		}
-
-		if event.version_directive != nil {
-			implicit = false
-			if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) {
-				return false
-			}
-			if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) {
-				return false
-			}
-			if !yaml_emitter_write_indent(emitter) {
-				return false
-			}
-		}
-
-		if len(event.tag_directives) > 0 {
-			implicit = false
-			for i := 0; i < len(event.tag_directives); i++ {
-				tag_directive := &event.tag_directives[i]
-				if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) {
-					return false
-				}
-				if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) {
-					return false
-				}
-				if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) {
-					return false
-				}
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-			}
-		}
-
-		if yaml_emitter_check_empty_document(emitter) {
-			implicit = false
-		}
-		if !implicit {
-			if !yaml_emitter_write_indent(emitter) {
-				return false
-			}
-			if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
-				return false
-			}
-			if emitter.canonical || true {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-			}
-		}
-
-		if len(emitter.head_comment) > 0 {
-			if !yaml_emitter_process_head_comment(emitter) {
-				return false
-			}
-			if !put_break(emitter) {
-				return false
-			}
-		}
-
-		emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE
-		return true
-	}
-
-	if event.typ == yaml_STREAM_END_EVENT {
-		if emitter.open_ended {
-			if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
-				return false
-			}
-			if !yaml_emitter_write_indent(emitter) {
-				return false
-			}
-		}
-		if !yaml_emitter_flush(emitter) {
-			return false
-		}
-		emitter.state = yaml_EMIT_END_STATE
-		return true
-	}
-
-	return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END")
-}
-
-// Expect the root node.
-func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE)
-
-	if !yaml_emitter_process_head_comment(emitter) {
-		return false
-	}
-	if !yaml_emitter_emit_node(emitter, event, true, false, false, false) {
-		return false
-	}
-	if !yaml_emitter_process_line_comment(emitter) {
-		return false
-	}
-	if !yaml_emitter_process_foot_comment(emitter) {
-		return false
-	}
-	return true
-}
-
-// Expect DOCUMENT-END.
-func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	if event.typ != yaml_DOCUMENT_END_EVENT {
-		return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END")
-	}
-	// [Go] Force document foot separation.
-	emitter.foot_indent = 0
-	if !yaml_emitter_process_foot_comment(emitter) {
-		return false
-	}
-	emitter.foot_indent = -1
-	if !yaml_emitter_write_indent(emitter) {
-		return false
-	}
-	if !event.implicit {
-		// [Go] Allocate the slice elsewhere.
-		if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
-			return false
-		}
-		if !yaml_emitter_write_indent(emitter) {
-			return false
-		}
-	}
-	if !yaml_emitter_flush(emitter) {
-		return false
-	}
-	emitter.state = yaml_EMIT_DOCUMENT_START_STATE
-	emitter.tag_directives = emitter.tag_directives[:0]
-	return true
-}
-
-// Expect a flow item node.
-func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool {
-	if first {
-		if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) {
-			return false
-		}
-		if !yaml_emitter_increase_indent(emitter, true, false) {
-			return false
-		}
-		emitter.flow_level++
-	}
-
-	if event.typ == yaml_SEQUENCE_END_EVENT {
-		if emitter.canonical && !first && !trail {
-			if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
-				return false
-			}
-		}
-		emitter.flow_level--
-		emitter.indent = emitter.indents[len(emitter.indents)-1]
-		emitter.indents = emitter.indents[:len(emitter.indents)-1]
-		if emitter.column == 0 || emitter.canonical && !first {
-			if !yaml_emitter_write_indent(emitter) {
-				return false
-			}
-		}
-		if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) {
-			return false
-		}
-		if !yaml_emitter_process_line_comment(emitter) {
-			return false
-		}
-		if !yaml_emitter_process_foot_comment(emitter) {
-			return false
-		}
-		emitter.state = emitter.states[len(emitter.states)-1]
-		emitter.states = emitter.states[:len(emitter.states)-1]
-
-		return true
-	}
-
-	if !first && !trail {
-		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
-			return false
-		}
-	}
-
-	if !yaml_emitter_process_head_comment(emitter) {
-		return false
-	}
-	if emitter.column == 0 {
-		if !yaml_emitter_write_indent(emitter) {
-			return false
-		}
-	}
-
-	if emitter.canonical || emitter.column > emitter.best_width {
-		if !yaml_emitter_write_indent(emitter) {
-			return false
-		}
-	}
-	if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
-		emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE)
-	} else {
-		emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
-	}
-	if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
-		return false
-	}
-	if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
-		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
-			return false
-		}
-	}
-	if !yaml_emitter_process_line_comment(emitter) {
-		return false
-	}
-	if !yaml_emitter_process_foot_comment(emitter) {
-		return false
-	}
-	return true
-}
-
-// Expect a flow key node.
-func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool {
-	if first {
-		if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) {
-			return false
-		}
-		if !yaml_emitter_increase_indent(emitter, true, false) {
-			return false
-		}
-		emitter.flow_level++
-	}
-
-	if event.typ == yaml_MAPPING_END_EVENT {
-		if (emitter.canonical || len(emitter.head_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0) && !first && !trail {
-			if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
-				return false
-			}
-		}
-		if !yaml_emitter_process_head_comment(emitter) {
-			return false
-		}
-		emitter.flow_level--
-		emitter.indent = emitter.indents[len(emitter.indents)-1]
-		emitter.indents = emitter.indents[:len(emitter.indents)-1]
-		if emitter.canonical && !first {
-			if !yaml_emitter_write_indent(emitter) {
-				return false
-			}
-		}
-		if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) {
-			return false
-		}
-		if !yaml_emitter_process_line_comment(emitter) {
-			return false
-		}
-		if !yaml_emitter_process_foot_comment(emitter) {
-			return false
-		}
-		emitter.state = emitter.states[len(emitter.states)-1]
-		emitter.states = emitter.states[:len(emitter.states)-1]
-		return true
-	}
-
-	if !first && !trail {
-		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
-			return false
-		}
-	}
-
-	if !yaml_emitter_process_head_comment(emitter) {
-		return false
-	}
-
-	if emitter.column == 0 {
-		if !yaml_emitter_write_indent(emitter) {
-			return false
-		}
-	}
-
-	if emitter.canonical || emitter.column > emitter.best_width {
-		if !yaml_emitter_write_indent(emitter) {
-			return false
-		}
-	}
-
-	if !emitter.canonical && yaml_emitter_check_simple_key(emitter) {
-		emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)
-		return yaml_emitter_emit_node(emitter, event, false, false, true, true)
-	}
-	if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) {
-		return false
-	}
-	emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE)
-	return yaml_emitter_emit_node(emitter, event, false, false, true, false)
-}
-
-// Expect a flow value node.
-func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
-	if simple {
-		if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
-			return false
-		}
-	} else {
-		if emitter.canonical || emitter.column > emitter.best_width {
-			if !yaml_emitter_write_indent(emitter) {
-				return false
-			}
-		}
-		if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) {
-			return false
-		}
-	}
-	if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
-		emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE)
-	} else {
-		emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
-	}
-	if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
-		return false
-	}
-	if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
-		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
-			return false
-		}
-	}
-	if !yaml_emitter_process_line_comment(emitter) {
-		return false
-	}
-	if !yaml_emitter_process_foot_comment(emitter) {
-		return false
-	}
-	return true
-}
-
-// Expect a block item node.
-func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
-	if first {
-		if !yaml_emitter_increase_indent(emitter, false, false) {
-			return false
-		}
-	}
-	if event.typ == yaml_SEQUENCE_END_EVENT {
-		emitter.indent = emitter.indents[len(emitter.indents)-1]
-		emitter.indents = emitter.indents[:len(emitter.indents)-1]
-		emitter.state = emitter.states[len(emitter.states)-1]
-		emitter.states = emitter.states[:len(emitter.states)-1]
-		return true
-	}
-	if !yaml_emitter_process_head_comment(emitter) {
-		return false
-	}
-	if !yaml_emitter_write_indent(emitter) {
-		return false
-	}
-	if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) {
-		return false
-	}
-	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE)
-	if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
-		return false
-	}
-	if !yaml_emitter_process_line_comment(emitter) {
-		return false
-	}
-	if !yaml_emitter_process_foot_comment(emitter) {
-		return false
-	}
-	return true
-}
-
-// Expect a block key node.
-func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
-	if first {
-		if !yaml_emitter_increase_indent(emitter, false, false) {
-			return false
-		}
-	}
-	if !yaml_emitter_process_head_comment(emitter) {
-		return false
-	}
-	if event.typ == yaml_MAPPING_END_EVENT {
-		emitter.indent = emitter.indents[len(emitter.indents)-1]
-		emitter.indents = emitter.indents[:len(emitter.indents)-1]
-		emitter.state = emitter.states[len(emitter.states)-1]
-		emitter.states = emitter.states[:len(emitter.states)-1]
-		return true
-	}
-	if !yaml_emitter_write_indent(emitter) {
-		return false
-	}
-	if len(emitter.line_comment) > 0 {
-		// [Go] A line comment was provided for the key. That's unusual as the
-		//      scanner associates line comments with the value. Either way,
-		//      save the line comment and render it appropriately later.
-		emitter.key_line_comment = emitter.line_comment
-		emitter.line_comment = nil
-	}
-	if yaml_emitter_check_simple_key(emitter) {
-		emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
-		return yaml_emitter_emit_node(emitter, event, false, false, true, true)
-	}
-	if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) {
-		return false
-	}
-	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE)
-	return yaml_emitter_emit_node(emitter, event, false, false, true, false)
-}
-
-// Expect a block value node.
-func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
-	if simple {
-		if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
-			return false
-		}
-	} else {
-		if !yaml_emitter_write_indent(emitter) {
-			return false
-		}
-		if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) {
-			return false
-		}
-	}
-	if len(emitter.key_line_comment) > 0 {
-		// [Go] Line comments are generally associated with the value, but when there's
-		//      no value on the same line as a mapping key they end up attached to the
-		//      key itself.
-		if event.typ == yaml_SCALAR_EVENT {
-			if len(emitter.line_comment) == 0 {
-				// A scalar is coming and it has no line comments by itself yet,
-				// so just let it handle the line comment as usual. If it has a
-				// line comment, we can't have both so the one from the key is lost.
-				emitter.line_comment = emitter.key_line_comment
-				emitter.key_line_comment = nil
-			}
-		} else if event.sequence_style() != yaml_FLOW_SEQUENCE_STYLE && (event.typ == yaml_MAPPING_START_EVENT || event.typ == yaml_SEQUENCE_START_EVENT) {
-			// An indented block follows, so write the comment right now.
-			emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment
-			if !yaml_emitter_process_line_comment(emitter) {
-				return false
-			}
-			emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment
-		}
-	}
-	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
-	if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
-		return false
-	}
-	if !yaml_emitter_process_line_comment(emitter) {
-		return false
-	}
-	if !yaml_emitter_process_foot_comment(emitter) {
-		return false
-	}
-	return true
-}
-
-func yaml_emitter_silent_nil_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	return event.typ == yaml_SCALAR_EVENT && event.implicit && !emitter.canonical && len(emitter.scalar_data.value) == 0
-}
-
-// Expect a node.
-func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
-	root bool, sequence bool, mapping bool, simple_key bool) bool {
-
-	emitter.root_context = root
-	emitter.sequence_context = sequence
-	emitter.mapping_context = mapping
-	emitter.simple_key_context = simple_key
-
-	switch event.typ {
-	case yaml_ALIAS_EVENT:
-		return yaml_emitter_emit_alias(emitter, event)
-	case yaml_SCALAR_EVENT:
-		return yaml_emitter_emit_scalar(emitter, event)
-	case yaml_SEQUENCE_START_EVENT:
-		return yaml_emitter_emit_sequence_start(emitter, event)
-	case yaml_MAPPING_START_EVENT:
-		return yaml_emitter_emit_mapping_start(emitter, event)
-	default:
-		return yaml_emitter_set_emitter_error(emitter,
-			fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ))
-	}
-}
-
-// Expect ALIAS.
-func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	if !yaml_emitter_process_anchor(emitter) {
-		return false
-	}
-	emitter.state = emitter.states[len(emitter.states)-1]
-	emitter.states = emitter.states[:len(emitter.states)-1]
-	return true
-}
-
-// Expect SCALAR.
-func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	if !yaml_emitter_select_scalar_style(emitter, event) {
-		return false
-	}
-	if !yaml_emitter_process_anchor(emitter) {
-		return false
-	}
-	if !yaml_emitter_process_tag(emitter) {
-		return false
-	}
-	if !yaml_emitter_increase_indent(emitter, true, false) {
-		return false
-	}
-	if !yaml_emitter_process_scalar(emitter) {
-		return false
-	}
-	emitter.indent = emitter.indents[len(emitter.indents)-1]
-	emitter.indents = emitter.indents[:len(emitter.indents)-1]
-	emitter.state = emitter.states[len(emitter.states)-1]
-	emitter.states = emitter.states[:len(emitter.states)-1]
-	return true
-}
-
-// Expect SEQUENCE-START.
-func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	if !yaml_emitter_process_anchor(emitter) {
-		return false
-	}
-	if !yaml_emitter_process_tag(emitter) {
-		return false
-	}
-	if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE ||
-		yaml_emitter_check_empty_sequence(emitter) {
-		emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
-	} else {
-		emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
-	}
-	return true
-}
-
-// Expect MAPPING-START.
-func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-	if !yaml_emitter_process_anchor(emitter) {
-		return false
-	}
-	if !yaml_emitter_process_tag(emitter) {
-		return false
-	}
-	if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE ||
-		yaml_emitter_check_empty_mapping(emitter) {
-		emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
-	} else {
-		emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
-	}
-	return true
-}
-
-// Check if the document content is an empty scalar.
-func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool {
-	return false // [Go] Huh?
-}
-
-// Check if the next events represent an empty sequence.
-func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool {
-	if len(emitter.events)-emitter.events_head < 2 {
-		return false
-	}
-	return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT &&
-		emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT
-}
-
-// Check if the next events represent an empty mapping.
-func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool {
-	if len(emitter.events)-emitter.events_head < 2 {
-		return false
-	}
-	return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT &&
-		emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT
-}
-
-// Check if the next node can be expressed as a simple key.
-func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool {
-	length := 0
-	switch emitter.events[emitter.events_head].typ {
-	case yaml_ALIAS_EVENT:
-		length += len(emitter.anchor_data.anchor)
-	case yaml_SCALAR_EVENT:
-		if emitter.scalar_data.multiline {
-			return false
-		}
-		length += len(emitter.anchor_data.anchor) +
-			len(emitter.tag_data.handle) +
-			len(emitter.tag_data.suffix) +
-			len(emitter.scalar_data.value)
-	case yaml_SEQUENCE_START_EVENT:
-		if !yaml_emitter_check_empty_sequence(emitter) {
-			return false
-		}
-		length += len(emitter.anchor_data.anchor) +
-			len(emitter.tag_data.handle) +
-			len(emitter.tag_data.suffix)
-	case yaml_MAPPING_START_EVENT:
-		if !yaml_emitter_check_empty_mapping(emitter) {
-			return false
-		}
-		length += len(emitter.anchor_data.anchor) +
-			len(emitter.tag_data.handle) +
-			len(emitter.tag_data.suffix)
-	default:
-		return false
-	}
-	return length <= 128
-}
-
-// Determine an acceptable scalar style.
-func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-
-	no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0
-	if no_tag && !event.implicit && !event.quoted_implicit {
-		return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified")
-	}
-
-	style := event.scalar_style()
-	if style == yaml_ANY_SCALAR_STYLE {
-		style = yaml_PLAIN_SCALAR_STYLE
-	}
-	if emitter.canonical {
-		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-	}
-	if emitter.simple_key_context && emitter.scalar_data.multiline {
-		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-	}
-
-	if style == yaml_PLAIN_SCALAR_STYLE {
-		if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed ||
-			emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed {
-			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
-		}
-		if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) {
-			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
-		}
-		if no_tag && !event.implicit {
-			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
-		}
-	}
-	if style == yaml_SINGLE_QUOTED_SCALAR_STYLE {
-		if !emitter.scalar_data.single_quoted_allowed {
-			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-		}
-	}
-	if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE {
-		if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context {
-			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-		}
-	}
-
-	if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE {
-		emitter.tag_data.handle = []byte{'!'}
-	}
-	emitter.scalar_data.style = style
-	return true
-}
-
-// Write an anchor.
-func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
-	if emitter.anchor_data.anchor == nil {
-		return true
-	}
-	c := []byte{'&'}
-	if emitter.anchor_data.alias {
-		c[0] = '*'
-	}
-	if !yaml_emitter_write_indicator(emitter, c, true, false, false) {
-		return false
-	}
-	return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor)
-}
-
-// Write a tag.
-func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool {
-	if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 {
-		return true
-	}
-	if len(emitter.tag_data.handle) > 0 {
-		if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) {
-			return false
-		}
-		if len(emitter.tag_data.suffix) > 0 {
-			if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
-				return false
-			}
-		}
-	} else {
-		// [Go] Allocate these slices elsewhere.
-		if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) {
-			return false
-		}
-		if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
-			return false
-		}
-		if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) {
-			return false
-		}
-	}
-	return true
-}
-
-// Write a scalar.
-func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {
-	switch emitter.scalar_data.style {
-	case yaml_PLAIN_SCALAR_STYLE:
-		return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
-	case yaml_SINGLE_QUOTED_SCALAR_STYLE:
-		return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
-	case yaml_DOUBLE_QUOTED_SCALAR_STYLE:
-		return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
-	case yaml_LITERAL_SCALAR_STYLE:
-		return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value)
-
-	case yaml_FOLDED_SCALAR_STYLE:
-		return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value)
-	}
-	panic("unknown scalar style")
-}
-
-// Write a head comment.
-func yaml_emitter_process_head_comment(emitter *yaml_emitter_t) bool {
-	if len(emitter.tail_comment) > 0 {
-		if !yaml_emitter_write_indent(emitter) {
-			return false
-		}
-		if !yaml_emitter_write_comment(emitter, emitter.tail_comment) {
-			return false
-		}
-		emitter.tail_comment = emitter.tail_comment[:0]
-		emitter.foot_indent = emitter.indent
-		if emitter.foot_indent < 0 {
-			emitter.foot_indent = 0
-		}
-	}
-
-	if len(emitter.head_comment) == 0 {
-		return true
-	}
-	if !yaml_emitter_write_indent(emitter) {
-		return false
-	}
-	if !yaml_emitter_write_comment(emitter, emitter.head_comment) {
-		return false
-	}
-	emitter.head_comment = emitter.head_comment[:0]
-	return true
-}
-
-// Write an line comment.
-func yaml_emitter_process_line_comment(emitter *yaml_emitter_t) bool {
-	if len(emitter.line_comment) == 0 {
-		return true
-	}
-	if !emitter.whitespace {
-		if !put(emitter, ' ') {
-			return false
-		}
-	}
-	if !yaml_emitter_write_comment(emitter, emitter.line_comment) {
-		return false
-	}
-	emitter.line_comment = emitter.line_comment[:0]
-	return true
-}
-
-// Write a foot comment.
-func yaml_emitter_process_foot_comment(emitter *yaml_emitter_t) bool {
-	if len(emitter.foot_comment) == 0 {
-		return true
-	}
-	if !yaml_emitter_write_indent(emitter) {
-		return false
-	}
-	if !yaml_emitter_write_comment(emitter, emitter.foot_comment) {
-		return false
-	}
-	emitter.foot_comment = emitter.foot_comment[:0]
-	emitter.foot_indent = emitter.indent
-	if emitter.foot_indent < 0 {
-		emitter.foot_indent = 0
-	}
-	return true
-}
-
-// Check if a %YAML directive is valid.
-func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool {
-	if version_directive.major != 1 || version_directive.minor != 1 {
-		return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive")
-	}
-	return true
-}
-
-// Check if a %TAG directive is valid.
-func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool {
-	handle := tag_directive.handle
-	prefix := tag_directive.prefix
-	if len(handle) == 0 {
-		return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty")
-	}
-	if handle[0] != '!' {
-		return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'")
-	}
-	if handle[len(handle)-1] != '!' {
-		return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'")
-	}
-	for i := 1; i < len(handle)-1; i += width(handle[i]) {
-		if !is_alpha(handle, i) {
-			return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only")
-		}
-	}
-	if len(prefix) == 0 {
-		return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty")
-	}
-	return true
-}
-
-// Check if an anchor is valid.
-func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool {
-	if len(anchor) == 0 {
-		problem := "anchor value must not be empty"
-		if alias {
-			problem = "alias value must not be empty"
-		}
-		return yaml_emitter_set_emitter_error(emitter, problem)
-	}
-	for i := 0; i < len(anchor); i += width(anchor[i]) {
-		if !is_alpha(anchor, i) {
-			problem := "anchor value must contain alphanumerical characters only"
-			if alias {
-				problem = "alias value must contain alphanumerical characters only"
-			}
-			return yaml_emitter_set_emitter_error(emitter, problem)
-		}
-	}
-	emitter.anchor_data.anchor = anchor
-	emitter.anchor_data.alias = alias
-	return true
-}
-
-// Check if a tag is valid.
-func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool {
-	if len(tag) == 0 {
-		return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty")
-	}
-	for i := 0; i < len(emitter.tag_directives); i++ {
-		tag_directive := &emitter.tag_directives[i]
-		if bytes.HasPrefix(tag, tag_directive.prefix) {
-			emitter.tag_data.handle = tag_directive.handle
-			emitter.tag_data.suffix = tag[len(tag_directive.prefix):]
-			return true
-		}
-	}
-	emitter.tag_data.suffix = tag
-	return true
-}
-
-// Check if a scalar is valid.
-func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
-	var (
-		block_indicators   = false
-		flow_indicators    = false
-		line_breaks        = false
-		special_characters = false
-		tab_characters     = false
-
-		leading_space  = false
-		leading_break  = false
-		trailing_space = false
-		trailing_break = false
-		break_space    = false
-		space_break    = false
-
-		preceded_by_whitespace = false
-		followed_by_whitespace = false
-		previous_space         = false
-		previous_break         = false
-	)
-
-	emitter.scalar_data.value = value
-
-	if len(value) == 0 {
-		emitter.scalar_data.multiline = false
-		emitter.scalar_data.flow_plain_allowed = false
-		emitter.scalar_data.block_plain_allowed = true
-		emitter.scalar_data.single_quoted_allowed = true
-		emitter.scalar_data.block_allowed = false
-		return true
-	}
-
-	if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) {
-		block_indicators = true
-		flow_indicators = true
-	}
-
-	preceded_by_whitespace = true
-	for i, w := 0, 0; i < len(value); i += w {
-		w = width(value[i])
-		followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
-
-		if i == 0 {
-			switch value[i] {
-			case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
-				flow_indicators = true
-				block_indicators = true
-			case '?', ':':
-				flow_indicators = true
-				if followed_by_whitespace {
-					block_indicators = true
-				}
-			case '-':
-				if followed_by_whitespace {
-					flow_indicators = true
-					block_indicators = true
-				}
-			}
-		} else {
-			switch value[i] {
-			case ',', '?', '[', ']', '{', '}':
-				flow_indicators = true
-			case ':':
-				flow_indicators = true
-				if followed_by_whitespace {
-					block_indicators = true
-				}
-			case '#':
-				if preceded_by_whitespace {
-					flow_indicators = true
-					block_indicators = true
-				}
-			}
-		}
-
-		if value[i] == '\t' {
-			tab_characters = true
-		} else if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode {
-			special_characters = true
-		}
-		if is_space(value, i) {
-			if i == 0 {
-				leading_space = true
-			}
-			if i+width(value[i]) == len(value) {
-				trailing_space = true
-			}
-			if previous_break {
-				break_space = true
-			}
-			previous_space = true
-			previous_break = false
-		} else if is_break(value, i) {
-			line_breaks = true
-			if i == 0 {
-				leading_break = true
-			}
-			if i+width(value[i]) == len(value) {
-				trailing_break = true
-			}
-			if previous_space {
-				space_break = true
-			}
-			previous_space = false
-			previous_break = true
-		} else {
-			previous_space = false
-			previous_break = false
-		}
-
-		// [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
-		preceded_by_whitespace = is_blankz(value, i)
-	}
-
-	emitter.scalar_data.multiline = line_breaks
-	emitter.scalar_data.flow_plain_allowed = true
-	emitter.scalar_data.block_plain_allowed = true
-	emitter.scalar_data.single_quoted_allowed = true
-	emitter.scalar_data.block_allowed = true
-
-	if leading_space || leading_break || trailing_space || trailing_break {
-		emitter.scalar_data.flow_plain_allowed = false
-		emitter.scalar_data.block_plain_allowed = false
-	}
-	if trailing_space {
-		emitter.scalar_data.block_allowed = false
-	}
-	if break_space {
-		emitter.scalar_data.flow_plain_allowed = false
-		emitter.scalar_data.block_plain_allowed = false
-		emitter.scalar_data.single_quoted_allowed = false
-	}
-	if space_break || tab_characters || special_characters {
-		emitter.scalar_data.flow_plain_allowed = false
-		emitter.scalar_data.block_plain_allowed = false
-		emitter.scalar_data.single_quoted_allowed = false
-	}
-	if space_break || special_characters {
-		emitter.scalar_data.block_allowed = false
-	}
-	if line_breaks {
-		emitter.scalar_data.flow_plain_allowed = false
-		emitter.scalar_data.block_plain_allowed = false
-	}
-	if flow_indicators {
-		emitter.scalar_data.flow_plain_allowed = false
-	}
-	if block_indicators {
-		emitter.scalar_data.block_plain_allowed = false
-	}
-	return true
-}
-
-// Check if the event data is valid.
-func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-
-	emitter.anchor_data.anchor = nil
-	emitter.tag_data.handle = nil
-	emitter.tag_data.suffix = nil
-	emitter.scalar_data.value = nil
-
-	if len(event.head_comment) > 0 {
-		emitter.head_comment = event.head_comment
-	}
-	if len(event.line_comment) > 0 {
-		emitter.line_comment = event.line_comment
-	}
-	if len(event.foot_comment) > 0 {
-		emitter.foot_comment = event.foot_comment
-	}
-	if len(event.tail_comment) > 0 {
-		emitter.tail_comment = event.tail_comment
-	}
-
-	switch event.typ {
-	case yaml_ALIAS_EVENT:
-		if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) {
-			return false
-		}
-
-	case yaml_SCALAR_EVENT:
-		if len(event.anchor) > 0 {
-			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
-				return false
-			}
-		}
-		if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) {
-			if !yaml_emitter_analyze_tag(emitter, event.tag) {
-				return false
-			}
-		}
-		if !yaml_emitter_analyze_scalar(emitter, event.value) {
-			return false
-		}
-
-	case yaml_SEQUENCE_START_EVENT:
-		if len(event.anchor) > 0 {
-			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
-				return false
-			}
-		}
-		if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
-			if !yaml_emitter_analyze_tag(emitter, event.tag) {
-				return false
-			}
-		}
-
-	case yaml_MAPPING_START_EVENT:
-		if len(event.anchor) > 0 {
-			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
-				return false
-			}
-		}
-		if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
-			if !yaml_emitter_analyze_tag(emitter, event.tag) {
-				return false
-			}
-		}
-	}
-	return true
-}
-
-// Write the BOM character.
-func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool {
-	if !flush(emitter) {
-		return false
-	}
-	pos := emitter.buffer_pos
-	emitter.buffer[pos+0] = '\xEF'
-	emitter.buffer[pos+1] = '\xBB'
-	emitter.buffer[pos+2] = '\xBF'
-	emitter.buffer_pos += 3
-	return true
-}
-
-func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool {
-	indent := emitter.indent
-	if indent < 0 {
-		indent = 0
-	}
-	if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) {
-		if !put_break(emitter) {
-			return false
-		}
-	}
-	if emitter.foot_indent == indent {
-		if !put_break(emitter) {
-			return false
-		}
-	}
-	for emitter.column < indent {
-		if !put(emitter, ' ') {
-			return false
-		}
-	}
-	emitter.whitespace = true
-	//emitter.indention = true
-	emitter.space_above = false
-	emitter.foot_indent = -1
-	return true
-}
-
-func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool {
-	if need_whitespace && !emitter.whitespace {
-		if !put(emitter, ' ') {
-			return false
-		}
-	}
-	if !write_all(emitter, indicator) {
-		return false
-	}
-	emitter.whitespace = is_whitespace
-	emitter.indention = (emitter.indention && is_indention)
-	emitter.open_ended = false
-	return true
-}
-
-func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool {
-	if !write_all(emitter, value) {
-		return false
-	}
-	emitter.whitespace = false
-	emitter.indention = false
-	return true
-}
-
-func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool {
-	if !emitter.whitespace {
-		if !put(emitter, ' ') {
-			return false
-		}
-	}
-	if !write_all(emitter, value) {
-		return false
-	}
-	emitter.whitespace = false
-	emitter.indention = false
-	return true
-}
-
-func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool {
-	if need_whitespace && !emitter.whitespace {
-		if !put(emitter, ' ') {
-			return false
-		}
-	}
-	for i := 0; i < len(value); {
-		var must_write bool
-		switch value[i] {
-		case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']':
-			must_write = true
-		default:
-			must_write = is_alpha(value, i)
-		}
-		if must_write {
-			if !write(emitter, value, &i) {
-				return false
-			}
-		} else {
-			w := width(value[i])
-			for k := 0; k < w; k++ {
-				octet := value[i]
-				i++
-				if !put(emitter, '%') {
-					return false
-				}
-
-				c := octet >> 4
-				if c < 10 {
-					c += '0'
-				} else {
-					c += 'A' - 10
-				}
-				if !put(emitter, c) {
-					return false
-				}
-
-				c = octet & 0x0f
-				if c < 10 {
-					c += '0'
-				} else {
-					c += 'A' - 10
-				}
-				if !put(emitter, c) {
-					return false
-				}
-			}
-		}
-	}
-	emitter.whitespace = false
-	emitter.indention = false
-	return true
-}
-
-func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
-	if len(value) > 0 && !emitter.whitespace {
-		if !put(emitter, ' ') {
-			return false
-		}
-	}
-
-	spaces := false
-	breaks := false
-	for i := 0; i < len(value); {
-		if is_space(value, i) {
-			if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-				i += width(value[i])
-			} else {
-				if !write(emitter, value, &i) {
-					return false
-				}
-			}
-			spaces = true
-		} else if is_break(value, i) {
-			if !breaks && value[i] == '\n' {
-				if !put_break(emitter) {
-					return false
-				}
-			}
-			if !write_break(emitter, value, &i) {
-				return false
-			}
-			//emitter.indention = true
-			breaks = true
-		} else {
-			if breaks {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-			}
-			if !write(emitter, value, &i) {
-				return false
-			}
-			emitter.indention = false
-			spaces = false
-			breaks = false
-		}
-	}
-
-	if len(value) > 0 {
-		emitter.whitespace = false
-	}
-	emitter.indention = false
-	if emitter.root_context {
-		emitter.open_ended = true
-	}
-
-	return true
-}
-
-func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
-
-	if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) {
-		return false
-	}
-
-	spaces := false
-	breaks := false
-	for i := 0; i < len(value); {
-		if is_space(value, i) {
-			if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-				i += width(value[i])
-			} else {
-				if !write(emitter, value, &i) {
-					return false
-				}
-			}
-			spaces = true
-		} else if is_break(value, i) {
-			if !breaks && value[i] == '\n' {
-				if !put_break(emitter) {
-					return false
-				}
-			}
-			if !write_break(emitter, value, &i) {
-				return false
-			}
-			//emitter.indention = true
-			breaks = true
-		} else {
-			if breaks {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-			}
-			if value[i] == '\'' {
-				if !put(emitter, '\'') {
-					return false
-				}
-			}
-			if !write(emitter, value, &i) {
-				return false
-			}
-			emitter.indention = false
-			spaces = false
-			breaks = false
-		}
-	}
-	if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) {
-		return false
-	}
-	emitter.whitespace = false
-	emitter.indention = false
-	return true
-}
-
-func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
-	spaces := false
-	if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) {
-		return false
-	}
-
-	for i := 0; i < len(value); {
-		if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) ||
-			is_bom(value, i) || is_break(value, i) ||
-			value[i] == '"' || value[i] == '\\' {
-
-			octet := value[i]
-
-			var w int
-			var v rune
-			switch {
-			case octet&0x80 == 0x00:
-				w, v = 1, rune(octet&0x7F)
-			case octet&0xE0 == 0xC0:
-				w, v = 2, rune(octet&0x1F)
-			case octet&0xF0 == 0xE0:
-				w, v = 3, rune(octet&0x0F)
-			case octet&0xF8 == 0xF0:
-				w, v = 4, rune(octet&0x07)
-			}
-			for k := 1; k < w; k++ {
-				octet = value[i+k]
-				v = (v << 6) + (rune(octet) & 0x3F)
-			}
-			i += w
-
-			if !put(emitter, '\\') {
-				return false
-			}
-
-			var ok bool
-			switch v {
-			case 0x00:
-				ok = put(emitter, '0')
-			case 0x07:
-				ok = put(emitter, 'a')
-			case 0x08:
-				ok = put(emitter, 'b')
-			case 0x09:
-				ok = put(emitter, 't')
-			case 0x0A:
-				ok = put(emitter, 'n')
-			case 0x0b:
-				ok = put(emitter, 'v')
-			case 0x0c:
-				ok = put(emitter, 'f')
-			case 0x0d:
-				ok = put(emitter, 'r')
-			case 0x1b:
-				ok = put(emitter, 'e')
-			case 0x22:
-				ok = put(emitter, '"')
-			case 0x5c:
-				ok = put(emitter, '\\')
-			case 0x85:
-				ok = put(emitter, 'N')
-			case 0xA0:
-				ok = put(emitter, '_')
-			case 0x2028:
-				ok = put(emitter, 'L')
-			case 0x2029:
-				ok = put(emitter, 'P')
-			default:
-				if v <= 0xFF {
-					ok = put(emitter, 'x')
-					w = 2
-				} else if v <= 0xFFFF {
-					ok = put(emitter, 'u')
-					w = 4
-				} else {
-					ok = put(emitter, 'U')
-					w = 8
-				}
-				for k := (w - 1) * 4; ok && k >= 0; k -= 4 {
-					digit := byte((v >> uint(k)) & 0x0F)
-					if digit < 10 {
-						ok = put(emitter, digit+'0')
-					} else {
-						ok = put(emitter, digit+'A'-10)
-					}
-				}
-			}
-			if !ok {
-				return false
-			}
-			spaces = false
-		} else if is_space(value, i) {
-			if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-				if is_space(value, i+1) {
-					if !put(emitter, '\\') {
-						return false
-					}
-				}
-				i += width(value[i])
-			} else if !write(emitter, value, &i) {
-				return false
-			}
-			spaces = true
-		} else {
-			if !write(emitter, value, &i) {
-				return false
-			}
-			spaces = false
-		}
-	}
-	if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) {
-		return false
-	}
-	emitter.whitespace = false
-	emitter.indention = false
-	return true
-}
-
-func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool {
-	if is_space(value, 0) || is_break(value, 0) {
-		indent_hint := []byte{'0' + byte(emitter.best_indent)}
-		if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) {
-			return false
-		}
-	}
-
-	emitter.open_ended = false
-
-	var chomp_hint [1]byte
-	if len(value) == 0 {
-		chomp_hint[0] = '-'
-	} else {
-		i := len(value) - 1
-		for value[i]&0xC0 == 0x80 {
-			i--
-		}
-		if !is_break(value, i) {
-			chomp_hint[0] = '-'
-		} else if i == 0 {
-			chomp_hint[0] = '+'
-			emitter.open_ended = true
-		} else {
-			i--
-			for value[i]&0xC0 == 0x80 {
-				i--
-			}
-			if is_break(value, i) {
-				chomp_hint[0] = '+'
-				emitter.open_ended = true
-			}
-		}
-	}
-	if chomp_hint[0] != 0 {
-		if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) {
-			return false
-		}
-	}
-	return true
-}
-
-func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool {
-	if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) {
-		return false
-	}
-	if !yaml_emitter_write_block_scalar_hints(emitter, value) {
-		return false
-	}
-	if !yaml_emitter_process_line_comment(emitter) {
-		return false
-	}
-	//emitter.indention = true
-	emitter.whitespace = true
-	breaks := true
-	for i := 0; i < len(value); {
-		if is_break(value, i) {
-			if !write_break(emitter, value, &i) {
-				return false
-			}
-			//emitter.indention = true
-			breaks = true
-		} else {
-			if breaks {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-			}
-			if !write(emitter, value, &i) {
-				return false
-			}
-			emitter.indention = false
-			breaks = false
-		}
-	}
-
-	return true
-}
-
-func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool {
-	if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) {
-		return false
-	}
-	if !yaml_emitter_write_block_scalar_hints(emitter, value) {
-		return false
-	}
-	if !yaml_emitter_process_line_comment(emitter) {
-		return false
-	}
-
-	//emitter.indention = true
-	emitter.whitespace = true
-
-	breaks := true
-	leading_spaces := true
-	for i := 0; i < len(value); {
-		if is_break(value, i) {
-			if !breaks && !leading_spaces && value[i] == '\n' {
-				k := 0
-				for is_break(value, k) {
-					k += width(value[k])
-				}
-				if !is_blankz(value, k) {
-					if !put_break(emitter) {
-						return false
-					}
-				}
-			}
-			if !write_break(emitter, value, &i) {
-				return false
-			}
-			//emitter.indention = true
-			breaks = true
-		} else {
-			if breaks {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-				leading_spaces = is_blank(value, i)
-			}
-			if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width {
-				if !yaml_emitter_write_indent(emitter) {
-					return false
-				}
-				i += width(value[i])
-			} else {
-				if !write(emitter, value, &i) {
-					return false
-				}
-			}
-			emitter.indention = false
-			breaks = false
-		}
-	}
-	return true
-}
-
-func yaml_emitter_write_comment(emitter *yaml_emitter_t, comment []byte) bool {
-	breaks := false
-	pound := false
-	for i := 0; i < len(comment); {
-		if is_break(comment, i) {
-			if !write_break(emitter, comment, &i) {
-				return false
-			}
-			//emitter.indention = true
-			breaks = true
-			pound = false
-		} else {
-			if breaks && !yaml_emitter_write_indent(emitter) {
-				return false
-			}
-			if !pound {
-				if comment[i] != '#' && (!put(emitter, '#') || !put(emitter, ' ')) {
-					return false
-				}
-				pound = true
-			}
-			if !write(emitter, comment, &i) {
-				return false
-			}
-			emitter.indention = false
-			breaks = false
-		}
-	}
-	if !breaks && !put_break(emitter) {
-		return false
-	}
-
-	emitter.whitespace = true
-	//emitter.indention = true
-	return true
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/encode.go
@@ -1,577 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package yaml
-
-import (
-	"encoding"
-	"fmt"
-	"io"
-	"reflect"
-	"regexp"
-	"sort"
-	"strconv"
-	"strings"
-	"time"
-	"unicode/utf8"
-)
-
-type encoder struct {
-	emitter  yaml_emitter_t
-	event    yaml_event_t
-	out      []byte
-	flow     bool
-	indent   int
-	doneInit bool
-}
-
-func newEncoder() *encoder {
-	e := &encoder{}
-	yaml_emitter_initialize(&e.emitter)
-	yaml_emitter_set_output_string(&e.emitter, &e.out)
-	yaml_emitter_set_unicode(&e.emitter, true)
-	return e
-}
-
-func newEncoderWithWriter(w io.Writer) *encoder {
-	e := &encoder{}
-	yaml_emitter_initialize(&e.emitter)
-	yaml_emitter_set_output_writer(&e.emitter, w)
-	yaml_emitter_set_unicode(&e.emitter, true)
-	return e
-}
-
-func (e *encoder) init() {
-	if e.doneInit {
-		return
-	}
-	if e.indent == 0 {
-		e.indent = 4
-	}
-	e.emitter.best_indent = e.indent
-	yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
-	e.emit()
-	e.doneInit = true
-}
-
-func (e *encoder) finish() {
-	e.emitter.open_ended = false
-	yaml_stream_end_event_initialize(&e.event)
-	e.emit()
-}
-
-func (e *encoder) destroy() {
-	yaml_emitter_delete(&e.emitter)
-}
-
-func (e *encoder) emit() {
-	// This will internally delete the e.event value.
-	e.must(yaml_emitter_emit(&e.emitter, &e.event))
-}
-
-func (e *encoder) must(ok bool) {
-	if !ok {
-		msg := e.emitter.problem
-		if msg == "" {
-			msg = "unknown problem generating YAML content"
-		}
-		failf("%s", msg)
-	}
-}
-
-func (e *encoder) marshalDoc(tag string, in reflect.Value) {
-	e.init()
-	var node *Node
-	if in.IsValid() {
-		node, _ = in.Interface().(*Node)
-	}
-	if node != nil && node.Kind == DocumentNode {
-		e.nodev(in)
-	} else {
-		yaml_document_start_event_initialize(&e.event, nil, nil, true)
-		e.emit()
-		e.marshal(tag, in)
-		yaml_document_end_event_initialize(&e.event, true)
-		e.emit()
-	}
-}
-
-func (e *encoder) marshal(tag string, in reflect.Value) {
-	tag = shortTag(tag)
-	if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
-		e.nilv()
-		return
-	}
-	iface := in.Interface()
-	switch value := iface.(type) {
-	case *Node:
-		e.nodev(in)
-		return
-	case Node:
-		if !in.CanAddr() {
-			var n = reflect.New(in.Type()).Elem()
-			n.Set(in)
-			in = n
-		}
-		e.nodev(in.Addr())
-		return
-	case time.Time:
-		e.timev(tag, in)
-		return
-	case *time.Time:
-		e.timev(tag, in.Elem())
-		return
-	case time.Duration:
-		e.stringv(tag, reflect.ValueOf(value.String()))
-		return
-	case Marshaler:
-		v, err := value.MarshalYAML()
-		if err != nil {
-			fail(err)
-		}
-		if v == nil {
-			e.nilv()
-			return
-		}
-		e.marshal(tag, reflect.ValueOf(v))
-		return
-	case encoding.TextMarshaler:
-		text, err := value.MarshalText()
-		if err != nil {
-			fail(err)
-		}
-		in = reflect.ValueOf(string(text))
-	case nil:
-		e.nilv()
-		return
-	}
-	switch in.Kind() {
-	case reflect.Interface:
-		e.marshal(tag, in.Elem())
-	case reflect.Map:
-		e.mapv(tag, in)
-	case reflect.Ptr:
-		e.marshal(tag, in.Elem())
-	case reflect.Struct:
-		e.structv(tag, in)
-	case reflect.Slice, reflect.Array:
-		e.slicev(tag, in)
-	case reflect.String:
-		e.stringv(tag, in)
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		e.intv(tag, in)
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		e.uintv(tag, in)
-	case reflect.Float32, reflect.Float64:
-		e.floatv(tag, in)
-	case reflect.Bool:
-		e.boolv(tag, in)
-	default:
-		panic("cannot marshal type: " + in.Type().String())
-	}
-}
-
-func (e *encoder) mapv(tag string, in reflect.Value) {
-	e.mappingv(tag, func() {
-		keys := keyList(in.MapKeys())
-		sort.Sort(keys)
-		for _, k := range keys {
-			e.marshal("", k)
-			e.marshal("", in.MapIndex(k))
-		}
-	})
-}
-
-func (e *encoder) fieldByIndex(v reflect.Value, index []int) (field reflect.Value) {
-	for _, num := range index {
-		for {
-			if v.Kind() == reflect.Ptr {
-				if v.IsNil() {
-					return reflect.Value{}
-				}
-				v = v.Elem()
-				continue
-			}
-			break
-		}
-		v = v.Field(num)
-	}
-	return v
-}
-
-func (e *encoder) structv(tag string, in reflect.Value) {
-	sinfo, err := getStructInfo(in.Type())
-	if err != nil {
-		panic(err)
-	}
-	e.mappingv(tag, func() {
-		for _, info := range sinfo.FieldsList {
-			var value reflect.Value
-			if info.Inline == nil {
-				value = in.Field(info.Num)
-			} else {
-				value = e.fieldByIndex(in, info.Inline)
-				if !value.IsValid() {
-					continue
-				}
-			}
-			if info.OmitEmpty && isZero(value) {
-				continue
-			}
-			e.marshal("", reflect.ValueOf(info.Key))
-			e.flow = info.Flow
-			e.marshal("", value)
-		}
-		if sinfo.InlineMap >= 0 {
-			m := in.Field(sinfo.InlineMap)
-			if m.Len() > 0 {
-				e.flow = false
-				keys := keyList(m.MapKeys())
-				sort.Sort(keys)
-				for _, k := range keys {
-					if _, found := sinfo.FieldsMap[k.String()]; found {
-						panic(fmt.Sprintf("cannot have key %q in inlined map: conflicts with struct field", k.String()))
-					}
-					e.marshal("", k)
-					e.flow = false
-					e.marshal("", m.MapIndex(k))
-				}
-			}
-		}
-	})
-}
-
-func (e *encoder) mappingv(tag string, f func()) {
-	implicit := tag == ""
-	style := yaml_BLOCK_MAPPING_STYLE
-	if e.flow {
-		e.flow = false
-		style = yaml_FLOW_MAPPING_STYLE
-	}
-	yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
-	e.emit()
-	f()
-	yaml_mapping_end_event_initialize(&e.event)
-	e.emit()
-}
-
-func (e *encoder) slicev(tag string, in reflect.Value) {
-	implicit := tag == ""
-	style := yaml_BLOCK_SEQUENCE_STYLE
-	if e.flow {
-		e.flow = false
-		style = yaml_FLOW_SEQUENCE_STYLE
-	}
-	e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
-	e.emit()
-	n := in.Len()
-	for i := 0; i < n; i++ {
-		e.marshal("", in.Index(i))
-	}
-	e.must(yaml_sequence_end_event_initialize(&e.event))
-	e.emit()
-}
-
-// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
-//
-// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
-// in YAML 1.2 and by this package, but these should be marshalled quoted for
-// the time being for compatibility with other parsers.
-func isBase60Float(s string) (result bool) {
-	// Fast path.
-	if s == "" {
-		return false
-	}
-	c := s[0]
-	if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
-		return false
-	}
-	// Do the full match.
-	return base60float.MatchString(s)
-}
-
-// From http://yaml.org/type/float.html, except the regular expression there
-// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
-var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
-
-// isOldBool returns whether s is bool notation as defined in YAML 1.1.
-//
-// We continue to force strings that YAML 1.1 would interpret as booleans to be
-// rendered as quotes strings so that the marshalled output valid for YAML 1.1
-// parsing.
-func isOldBool(s string) (result bool) {
-	switch s {
-	case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON",
-		"n", "N", "no", "No", "NO", "off", "Off", "OFF":
-		return true
-	default:
-		return false
-	}
-}
-
-func (e *encoder) stringv(tag string, in reflect.Value) {
-	var style yaml_scalar_style_t
-	s := in.String()
-	canUsePlain := true
-	switch {
-	case !utf8.ValidString(s):
-		if tag == binaryTag {
-			failf("explicitly tagged !!binary data must be base64-encoded")
-		}
-		if tag != "" {
-			failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
-		}
-		// It can't be encoded directly as YAML so use a binary tag
-		// and encode it as base64.
-		tag = binaryTag
-		s = encodeBase64(s)
-	case tag == "":
-		// Check to see if it would resolve to a specific
-		// tag when encoded unquoted. If it doesn't,
-		// there's no need to quote it.
-		rtag, _ := resolve("", s)
-		canUsePlain = rtag == strTag && !(isBase60Float(s) || isOldBool(s))
-	}
-	// Note: it's possible for user code to emit invalid YAML
-	// if they explicitly specify a tag and a string containing
-	// text that's incompatible with that tag.
-	switch {
-	case strings.Contains(s, "\n"):
-		if e.flow {
-			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-		} else {
-			style = yaml_LITERAL_SCALAR_STYLE
-		}
-	case canUsePlain:
-		style = yaml_PLAIN_SCALAR_STYLE
-	default:
-		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-	}
-	e.emitScalar(s, "", tag, style, nil, nil, nil, nil)
-}
-
-func (e *encoder) boolv(tag string, in reflect.Value) {
-	var s string
-	if in.Bool() {
-		s = "true"
-	} else {
-		s = "false"
-	}
-	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) intv(tag string, in reflect.Value) {
-	s := strconv.FormatInt(in.Int(), 10)
-	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) uintv(tag string, in reflect.Value) {
-	s := strconv.FormatUint(in.Uint(), 10)
-	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) timev(tag string, in reflect.Value) {
-	t := in.Interface().(time.Time)
-	s := t.Format(time.RFC3339Nano)
-	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) floatv(tag string, in reflect.Value) {
-	// Issue #352: When formatting, use the precision of the underlying value
-	precision := 64
-	if in.Kind() == reflect.Float32 {
-		precision = 32
-	}
-
-	s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
-	switch s {
-	case "+Inf":
-		s = ".inf"
-	case "-Inf":
-		s = "-.inf"
-	case "NaN":
-		s = ".nan"
-	}
-	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) nilv() {
-	e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
-}
-
-func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot, tail []byte) {
-	// TODO Kill this function. Replace all initialize calls by their underlining Go literals.
-	implicit := tag == ""
-	if !implicit {
-		tag = longTag(tag)
-	}
-	e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
-	e.event.head_comment = head
-	e.event.line_comment = line
-	e.event.foot_comment = foot
-	e.event.tail_comment = tail
-	e.emit()
-}
-
-func (e *encoder) nodev(in reflect.Value) {
-	e.node(in.Interface().(*Node), "")
-}
-
-func (e *encoder) node(node *Node, tail string) {
-	// Zero nodes behave as nil.
-	if node.Kind == 0 && node.IsZero() {
-		e.nilv()
-		return
-	}
-
-	// If the tag was not explicitly requested, and dropping it won't change the
-	// implicit tag of the value, don't include it in the presentation.
-	var tag = node.Tag
-	var stag = shortTag(tag)
-	var forceQuoting bool
-	if tag != "" && node.Style&TaggedStyle == 0 {
-		if node.Kind == ScalarNode {
-			if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 {
-				tag = ""
-			} else {
-				rtag, _ := resolve("", node.Value)
-				if rtag == stag {
-					tag = ""
-				} else if stag == strTag {
-					tag = ""
-					forceQuoting = true
-				}
-			}
-		} else {
-			var rtag string
-			switch node.Kind {
-			case MappingNode:
-				rtag = mapTag
-			case SequenceNode:
-				rtag = seqTag
-			}
-			if rtag == stag {
-				tag = ""
-			}
-		}
-	}
-
-	switch node.Kind {
-	case DocumentNode:
-		yaml_document_start_event_initialize(&e.event, nil, nil, true)
-		e.event.head_comment = []byte(node.HeadComment)
-		e.emit()
-		for _, node := range node.Content {
-			e.node(node, "")
-		}
-		yaml_document_end_event_initialize(&e.event, true)
-		e.event.foot_comment = []byte(node.FootComment)
-		e.emit()
-
-	case SequenceNode:
-		style := yaml_BLOCK_SEQUENCE_STYLE
-		if node.Style&FlowStyle != 0 {
-			style = yaml_FLOW_SEQUENCE_STYLE
-		}
-		e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style))
-		e.event.head_comment = []byte(node.HeadComment)
-		e.emit()
-		for _, node := range node.Content {
-			e.node(node, "")
-		}
-		e.must(yaml_sequence_end_event_initialize(&e.event))
-		e.event.line_comment = []byte(node.LineComment)
-		e.event.foot_comment = []byte(node.FootComment)
-		e.emit()
-
-	case MappingNode:
-		style := yaml_BLOCK_MAPPING_STYLE
-		if node.Style&FlowStyle != 0 {
-			style = yaml_FLOW_MAPPING_STYLE
-		}
-		yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style)
-		e.event.tail_comment = []byte(tail)
-		e.event.head_comment = []byte(node.HeadComment)
-		e.emit()
-
-		// The tail logic below moves the foot comment of prior keys to the following key,
-		// since the value for each key may be a nested structure and the foot needs to be
-		// processed only the entirety of the value is streamed. The last tail is processed
-		// with the mapping end event.
-		var tail string
-		for i := 0; i+1 < len(node.Content); i += 2 {
-			k := node.Content[i]
-			foot := k.FootComment
-			if foot != "" {
-				kopy := *k
-				kopy.FootComment = ""
-				k = &kopy
-			}
-			e.node(k, tail)
-			tail = foot
-
-			v := node.Content[i+1]
-			e.node(v, "")
-		}
-
-		yaml_mapping_end_event_initialize(&e.event)
-		e.event.tail_comment = []byte(tail)
-		e.event.line_comment = []byte(node.LineComment)
-		e.event.foot_comment = []byte(node.FootComment)
-		e.emit()
-
-	case AliasNode:
-		yaml_alias_event_initialize(&e.event, []byte(node.Value))
-		e.event.head_comment = []byte(node.HeadComment)
-		e.event.line_comment = []byte(node.LineComment)
-		e.event.foot_comment = []byte(node.FootComment)
-		e.emit()
-
-	case ScalarNode:
-		value := node.Value
-		if !utf8.ValidString(value) {
-			if stag == binaryTag {
-				failf("explicitly tagged !!binary data must be base64-encoded")
-			}
-			if stag != "" {
-				failf("cannot marshal invalid UTF-8 data as %s", stag)
-			}
-			// It can't be encoded directly as YAML so use a binary tag
-			// and encode it as base64.
-			tag = binaryTag
-			value = encodeBase64(value)
-		}
-
-		style := yaml_PLAIN_SCALAR_STYLE
-		switch {
-		case node.Style&DoubleQuotedStyle != 0:
-			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-		case node.Style&SingleQuotedStyle != 0:
-			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
-		case node.Style&LiteralStyle != 0:
-			style = yaml_LITERAL_SCALAR_STYLE
-		case node.Style&FoldedStyle != 0:
-			style = yaml_FOLDED_SCALAR_STYLE
-		case strings.Contains(value, "\n"):
-			style = yaml_LITERAL_SCALAR_STYLE
-		case forceQuoting:
-			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-		}
-
-		e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail))
-	default:
-		failf("cannot encode node with unknown kind %d", node.Kind)
-	}
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/LICENSE
@@ -1,50 +0,0 @@
-
-This project is covered by two different licenses: MIT and Apache.
-
-#### MIT License ####
-
-The following files were ported to Go from C files of libyaml, and thus
-are still covered by their original MIT license, with the additional
-copyright staring in 2011 when the project was ported over:
-
-    apic.go emitterc.go parserc.go readerc.go scannerc.go
-    writerc.go yamlh.go yamlprivateh.go
-
-Copyright (c) 2006-2010 Kirill Simonov
-Copyright (c) 2006-2011 Kirill Simonov
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-### Apache License ###
-
-All the remaining project files are covered by the Apache license:
-
-Copyright (c) 2011-2019 Canonical Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
tools/review-tool/vendor/gopkg.in/yaml.v3/NOTICE
@@ -1,13 +0,0 @@
-Copyright 2011-2016 Canonical Ltd.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
tools/review-tool/vendor/gopkg.in/yaml.v3/parserc.go
@@ -1,1274 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
-	"bytes"
-)
-
-// The parser implements the following grammar:
-//
-// stream               ::= STREAM-START implicit_document? explicit_document* STREAM-END
-// implicit_document    ::= block_node DOCUMENT-END*
-// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-// block_node_or_indentless_sequence    ::=
-//                          ALIAS
-//                          | properties (block_content | indentless_block_sequence)?
-//                          | block_content
-//                          | indentless_block_sequence
-// block_node           ::= ALIAS
-//                          | properties block_content?
-//                          | block_content
-// flow_node            ::= ALIAS
-//                          | properties flow_content?
-//                          | flow_content
-// properties           ::= TAG ANCHOR? | ANCHOR TAG?
-// block_content        ::= block_collection | flow_collection | SCALAR
-// flow_content         ::= flow_collection | SCALAR
-// block_collection     ::= block_sequence | block_mapping
-// flow_collection      ::= flow_sequence | flow_mapping
-// block_sequence       ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
-// indentless_sequence  ::= (BLOCK-ENTRY block_node?)+
-// block_mapping        ::= BLOCK-MAPPING_START
-//                          ((KEY block_node_or_indentless_sequence?)?
-//                          (VALUE block_node_or_indentless_sequence?)?)*
-//                          BLOCK-END
-// flow_sequence        ::= FLOW-SEQUENCE-START
-//                          (flow_sequence_entry FLOW-ENTRY)*
-//                          flow_sequence_entry?
-//                          FLOW-SEQUENCE-END
-// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// flow_mapping         ::= FLOW-MAPPING-START
-//                          (flow_mapping_entry FLOW-ENTRY)*
-//                          flow_mapping_entry?
-//                          FLOW-MAPPING-END
-// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-
-// Peek the next token in the token queue.
-func peek_token(parser *yaml_parser_t) *yaml_token_t {
-	if parser.token_available || yaml_parser_fetch_more_tokens(parser) {
-		token := &parser.tokens[parser.tokens_head]
-		yaml_parser_unfold_comments(parser, token)
-		return token
-	}
-	return nil
-}
-
-// yaml_parser_unfold_comments walks through the comments queue and joins all
-// comments behind the position of the provided token into the respective
-// top-level comment slices in the parser.
-func yaml_parser_unfold_comments(parser *yaml_parser_t, token *yaml_token_t) {
-	for parser.comments_head < len(parser.comments) && token.start_mark.index >= parser.comments[parser.comments_head].token_mark.index {
-		comment := &parser.comments[parser.comments_head]
-		if len(comment.head) > 0 {
-			if token.typ == yaml_BLOCK_END_TOKEN {
-				// No heads on ends, so keep comment.head for a follow up token.
-				break
-			}
-			if len(parser.head_comment) > 0 {
-				parser.head_comment = append(parser.head_comment, '\n')
-			}
-			parser.head_comment = append(parser.head_comment, comment.head...)
-		}
-		if len(comment.foot) > 0 {
-			if len(parser.foot_comment) > 0 {
-				parser.foot_comment = append(parser.foot_comment, '\n')
-			}
-			parser.foot_comment = append(parser.foot_comment, comment.foot...)
-		}
-		if len(comment.line) > 0 {
-			if len(parser.line_comment) > 0 {
-				parser.line_comment = append(parser.line_comment, '\n')
-			}
-			parser.line_comment = append(parser.line_comment, comment.line...)
-		}
-		*comment = yaml_comment_t{}
-		parser.comments_head++
-	}
-}
-
-// Remove the next token from the queue (must be called after peek_token).
-func skip_token(parser *yaml_parser_t) {
-	parser.token_available = false
-	parser.tokens_parsed++
-	parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN
-	parser.tokens_head++
-}
-
-// Get the next event.
-func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {
-	// Erase the event object.
-	*event = yaml_event_t{}
-
-	// No events after the end of the stream or error.
-	if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE {
-		return true
-	}
-
-	// Generate the next event.
-	return yaml_parser_state_machine(parser, event)
-}
-
-// Set parser error.
-func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool {
-	parser.error = yaml_PARSER_ERROR
-	parser.problem = problem
-	parser.problem_mark = problem_mark
-	return false
-}
-
-func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool {
-	parser.error = yaml_PARSER_ERROR
-	parser.context = context
-	parser.context_mark = context_mark
-	parser.problem = problem
-	parser.problem_mark = problem_mark
-	return false
-}
-
-// State dispatcher.
-func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {
-	//trace("yaml_parser_state_machine", "state:", parser.state.String())
-
-	switch parser.state {
-	case yaml_PARSE_STREAM_START_STATE:
-		return yaml_parser_parse_stream_start(parser, event)
-
-	case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
-		return yaml_parser_parse_document_start(parser, event, true)
-
-	case yaml_PARSE_DOCUMENT_START_STATE:
-		return yaml_parser_parse_document_start(parser, event, false)
-
-	case yaml_PARSE_DOCUMENT_CONTENT_STATE:
-		return yaml_parser_parse_document_content(parser, event)
-
-	case yaml_PARSE_DOCUMENT_END_STATE:
-		return yaml_parser_parse_document_end(parser, event)
-
-	case yaml_PARSE_BLOCK_NODE_STATE:
-		return yaml_parser_parse_node(parser, event, true, false)
-
-	case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
-		return yaml_parser_parse_node(parser, event, true, true)
-
-	case yaml_PARSE_FLOW_NODE_STATE:
-		return yaml_parser_parse_node(parser, event, false, false)
-
-	case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
-		return yaml_parser_parse_block_sequence_entry(parser, event, true)
-
-	case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
-		return yaml_parser_parse_block_sequence_entry(parser, event, false)
-
-	case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
-		return yaml_parser_parse_indentless_sequence_entry(parser, event)
-
-	case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
-		return yaml_parser_parse_block_mapping_key(parser, event, true)
-
-	case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
-		return yaml_parser_parse_block_mapping_key(parser, event, false)
-
-	case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
-		return yaml_parser_parse_block_mapping_value(parser, event)
-
-	case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
-		return yaml_parser_parse_flow_sequence_entry(parser, event, true)
-
-	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
-		return yaml_parser_parse_flow_sequence_entry(parser, event, false)
-
-	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
-		return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)
-
-	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
-		return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)
-
-	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
-		return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)
-
-	case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
-		return yaml_parser_parse_flow_mapping_key(parser, event, true)
-
-	case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
-		return yaml_parser_parse_flow_mapping_key(parser, event, false)
-
-	case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
-		return yaml_parser_parse_flow_mapping_value(parser, event, false)
-
-	case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
-		return yaml_parser_parse_flow_mapping_value(parser, event, true)
-
-	default:
-		panic("invalid parser state")
-	}
-}
-
-// Parse the production:
-// stream   ::= STREAM-START implicit_document? explicit_document* STREAM-END
-//
-//	************
-func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-	if token.typ != yaml_STREAM_START_TOKEN {
-		return yaml_parser_set_parser_error(parser, "did not find expected <stream-start>", token.start_mark)
-	}
-	parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
-	*event = yaml_event_t{
-		typ:        yaml_STREAM_START_EVENT,
-		start_mark: token.start_mark,
-		end_mark:   token.end_mark,
-		encoding:   token.encoding,
-	}
-	skip_token(parser)
-	return true
-}
-
-// Parse the productions:
-// implicit_document    ::= block_node DOCUMENT-END*
-//
-//	*
-//
-// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-//
-//	*************************
-func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {
-
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	// Parse extra document end indicators.
-	if !implicit {
-		for token.typ == yaml_DOCUMENT_END_TOKEN {
-			skip_token(parser)
-			token = peek_token(parser)
-			if token == nil {
-				return false
-			}
-		}
-	}
-
-	if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN &&
-		token.typ != yaml_TAG_DIRECTIVE_TOKEN &&
-		token.typ != yaml_DOCUMENT_START_TOKEN &&
-		token.typ != yaml_STREAM_END_TOKEN {
-		// Parse an implicit document.
-		if !yaml_parser_process_directives(parser, nil, nil) {
-			return false
-		}
-		parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
-		parser.state = yaml_PARSE_BLOCK_NODE_STATE
-
-		var head_comment []byte
-		if len(parser.head_comment) > 0 {
-			// [Go] Scan the header comment backwards, and if an empty line is found, break
-			//      the header so the part before the last empty line goes into the
-			//      document header, while the bottom of it goes into a follow up event.
-			for i := len(parser.head_comment) - 1; i > 0; i-- {
-				if parser.head_comment[i] == '\n' {
-					if i == len(parser.head_comment)-1 {
-						head_comment = parser.head_comment[:i]
-						parser.head_comment = parser.head_comment[i+1:]
-						break
-					} else if parser.head_comment[i-1] == '\n' {
-						head_comment = parser.head_comment[:i-1]
-						parser.head_comment = parser.head_comment[i+1:]
-						break
-					}
-				}
-			}
-		}
-
-		*event = yaml_event_t{
-			typ:        yaml_DOCUMENT_START_EVENT,
-			start_mark: token.start_mark,
-			end_mark:   token.end_mark,
-
-			head_comment: head_comment,
-		}
-
-	} else if token.typ != yaml_STREAM_END_TOKEN {
-		// Parse an explicit document.
-		var version_directive *yaml_version_directive_t
-		var tag_directives []yaml_tag_directive_t
-		start_mark := token.start_mark
-		if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) {
-			return false
-		}
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ != yaml_DOCUMENT_START_TOKEN {
-			yaml_parser_set_parser_error(parser,
-				"did not find expected <document start>", token.start_mark)
-			return false
-		}
-		parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
-		parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE
-		end_mark := token.end_mark
-
-		*event = yaml_event_t{
-			typ:               yaml_DOCUMENT_START_EVENT,
-			start_mark:        start_mark,
-			end_mark:          end_mark,
-			version_directive: version_directive,
-			tag_directives:    tag_directives,
-			implicit:          false,
-		}
-		skip_token(parser)
-
-	} else {
-		// Parse the stream end.
-		parser.state = yaml_PARSE_END_STATE
-		*event = yaml_event_t{
-			typ:        yaml_STREAM_END_EVENT,
-			start_mark: token.start_mark,
-			end_mark:   token.end_mark,
-		}
-		skip_token(parser)
-	}
-
-	return true
-}
-
-// Parse the productions:
-// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-//
-//	***********
-func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	if token.typ == yaml_VERSION_DIRECTIVE_TOKEN ||
-		token.typ == yaml_TAG_DIRECTIVE_TOKEN ||
-		token.typ == yaml_DOCUMENT_START_TOKEN ||
-		token.typ == yaml_DOCUMENT_END_TOKEN ||
-		token.typ == yaml_STREAM_END_TOKEN {
-		parser.state = parser.states[len(parser.states)-1]
-		parser.states = parser.states[:len(parser.states)-1]
-		return yaml_parser_process_empty_scalar(parser, event,
-			token.start_mark)
-	}
-	return yaml_parser_parse_node(parser, event, true, false)
-}
-
-// Parse the productions:
-// implicit_document    ::= block_node DOCUMENT-END*
-//
-//	*************
-//
-// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	start_mark := token.start_mark
-	end_mark := token.start_mark
-
-	implicit := true
-	if token.typ == yaml_DOCUMENT_END_TOKEN {
-		end_mark = token.end_mark
-		skip_token(parser)
-		implicit = false
-	}
-
-	parser.tag_directives = parser.tag_directives[:0]
-
-	parser.state = yaml_PARSE_DOCUMENT_START_STATE
-	*event = yaml_event_t{
-		typ:        yaml_DOCUMENT_END_EVENT,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-		implicit:   implicit,
-	}
-	yaml_parser_set_event_comments(parser, event)
-	if len(event.head_comment) > 0 && len(event.foot_comment) == 0 {
-		event.foot_comment = event.head_comment
-		event.head_comment = nil
-	}
-	return true
-}
-
-func yaml_parser_set_event_comments(parser *yaml_parser_t, event *yaml_event_t) {
-	event.head_comment = parser.head_comment
-	event.line_comment = parser.line_comment
-	event.foot_comment = parser.foot_comment
-	parser.head_comment = nil
-	parser.line_comment = nil
-	parser.foot_comment = nil
-	parser.tail_comment = nil
-	parser.stem_comment = nil
-}
-
-// Parse the productions:
-// block_node_or_indentless_sequence    ::=
-//
-//	ALIAS
-//	*****
-//	| properties (block_content | indentless_block_sequence)?
-//	  **********  *
-//	| block_content | indentless_block_sequence
-//	  *
-//
-// block_node           ::= ALIAS
-//
-//	*****
-//	| properties block_content?
-//	  ********** *
-//	| block_content
-//	  *
-//
-// flow_node            ::= ALIAS
-//
-//	*****
-//	| properties flow_content?
-//	  ********** *
-//	| flow_content
-//	  *
-//
-// properties           ::= TAG ANCHOR? | ANCHOR TAG?
-//
-//	*************************
-//
-// block_content        ::= block_collection | flow_collection | SCALAR
-//
-//	******
-//
-// flow_content         ::= flow_collection | SCALAR
-//
-//	******
-func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {
-	//defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)()
-
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	if token.typ == yaml_ALIAS_TOKEN {
-		parser.state = parser.states[len(parser.states)-1]
-		parser.states = parser.states[:len(parser.states)-1]
-		*event = yaml_event_t{
-			typ:        yaml_ALIAS_EVENT,
-			start_mark: token.start_mark,
-			end_mark:   token.end_mark,
-			anchor:     token.value,
-		}
-		yaml_parser_set_event_comments(parser, event)
-		skip_token(parser)
-		return true
-	}
-
-	start_mark := token.start_mark
-	end_mark := token.start_mark
-
-	var tag_token bool
-	var tag_handle, tag_suffix, anchor []byte
-	var tag_mark yaml_mark_t
-	if token.typ == yaml_ANCHOR_TOKEN {
-		anchor = token.value
-		start_mark = token.start_mark
-		end_mark = token.end_mark
-		skip_token(parser)
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ == yaml_TAG_TOKEN {
-			tag_token = true
-			tag_handle = token.value
-			tag_suffix = token.suffix
-			tag_mark = token.start_mark
-			end_mark = token.end_mark
-			skip_token(parser)
-			token = peek_token(parser)
-			if token == nil {
-				return false
-			}
-		}
-	} else if token.typ == yaml_TAG_TOKEN {
-		tag_token = true
-		tag_handle = token.value
-		tag_suffix = token.suffix
-		start_mark = token.start_mark
-		tag_mark = token.start_mark
-		end_mark = token.end_mark
-		skip_token(parser)
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ == yaml_ANCHOR_TOKEN {
-			anchor = token.value
-			end_mark = token.end_mark
-			skip_token(parser)
-			token = peek_token(parser)
-			if token == nil {
-				return false
-			}
-		}
-	}
-
-	var tag []byte
-	if tag_token {
-		if len(tag_handle) == 0 {
-			tag = tag_suffix
-			tag_suffix = nil
-		} else {
-			for i := range parser.tag_directives {
-				if bytes.Equal(parser.tag_directives[i].handle, tag_handle) {
-					tag = append([]byte(nil), parser.tag_directives[i].prefix...)
-					tag = append(tag, tag_suffix...)
-					break
-				}
-			}
-			if len(tag) == 0 {
-				yaml_parser_set_parser_error_context(parser,
-					"while parsing a node", start_mark,
-					"found undefined tag handle", tag_mark)
-				return false
-			}
-		}
-	}
-
-	implicit := len(tag) == 0
-	if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN {
-		end_mark = token.end_mark
-		parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
-		*event = yaml_event_t{
-			typ:        yaml_SEQUENCE_START_EVENT,
-			start_mark: start_mark,
-			end_mark:   end_mark,
-			anchor:     anchor,
-			tag:        tag,
-			implicit:   implicit,
-			style:      yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
-		}
-		return true
-	}
-	if token.typ == yaml_SCALAR_TOKEN {
-		var plain_implicit, quoted_implicit bool
-		end_mark = token.end_mark
-		if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') {
-			plain_implicit = true
-		} else if len(tag) == 0 {
-			quoted_implicit = true
-		}
-		parser.state = parser.states[len(parser.states)-1]
-		parser.states = parser.states[:len(parser.states)-1]
-
-		*event = yaml_event_t{
-			typ:             yaml_SCALAR_EVENT,
-			start_mark:      start_mark,
-			end_mark:        end_mark,
-			anchor:          anchor,
-			tag:             tag,
-			value:           token.value,
-			implicit:        plain_implicit,
-			quoted_implicit: quoted_implicit,
-			style:           yaml_style_t(token.style),
-		}
-		yaml_parser_set_event_comments(parser, event)
-		skip_token(parser)
-		return true
-	}
-	if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN {
-		// [Go] Some of the events below can be merged as they differ only on style.
-		end_mark = token.end_mark
-		parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
-		*event = yaml_event_t{
-			typ:        yaml_SEQUENCE_START_EVENT,
-			start_mark: start_mark,
-			end_mark:   end_mark,
-			anchor:     anchor,
-			tag:        tag,
-			implicit:   implicit,
-			style:      yaml_style_t(yaml_FLOW_SEQUENCE_STYLE),
-		}
-		yaml_parser_set_event_comments(parser, event)
-		return true
-	}
-	if token.typ == yaml_FLOW_MAPPING_START_TOKEN {
-		end_mark = token.end_mark
-		parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
-		*event = yaml_event_t{
-			typ:        yaml_MAPPING_START_EVENT,
-			start_mark: start_mark,
-			end_mark:   end_mark,
-			anchor:     anchor,
-			tag:        tag,
-			implicit:   implicit,
-			style:      yaml_style_t(yaml_FLOW_MAPPING_STYLE),
-		}
-		yaml_parser_set_event_comments(parser, event)
-		return true
-	}
-	if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {
-		end_mark = token.end_mark
-		parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
-		*event = yaml_event_t{
-			typ:        yaml_SEQUENCE_START_EVENT,
-			start_mark: start_mark,
-			end_mark:   end_mark,
-			anchor:     anchor,
-			tag:        tag,
-			implicit:   implicit,
-			style:      yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
-		}
-		if parser.stem_comment != nil {
-			event.head_comment = parser.stem_comment
-			parser.stem_comment = nil
-		}
-		return true
-	}
-	if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN {
-		end_mark = token.end_mark
-		parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
-		*event = yaml_event_t{
-			typ:        yaml_MAPPING_START_EVENT,
-			start_mark: start_mark,
-			end_mark:   end_mark,
-			anchor:     anchor,
-			tag:        tag,
-			implicit:   implicit,
-			style:      yaml_style_t(yaml_BLOCK_MAPPING_STYLE),
-		}
-		if parser.stem_comment != nil {
-			event.head_comment = parser.stem_comment
-			parser.stem_comment = nil
-		}
-		return true
-	}
-	if len(anchor) > 0 || len(tag) > 0 {
-		parser.state = parser.states[len(parser.states)-1]
-		parser.states = parser.states[:len(parser.states)-1]
-
-		*event = yaml_event_t{
-			typ:             yaml_SCALAR_EVENT,
-			start_mark:      start_mark,
-			end_mark:        end_mark,
-			anchor:          anchor,
-			tag:             tag,
-			implicit:        implicit,
-			quoted_implicit: false,
-			style:           yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
-		}
-		return true
-	}
-
-	context := "while parsing a flow node"
-	if block {
-		context = "while parsing a block node"
-	}
-	yaml_parser_set_parser_error_context(parser, context, start_mark,
-		"did not find expected node content", token.start_mark)
-	return false
-}
-
-// Parse the productions:
-// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
-//
-//	********************  *********** *             *********
-func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
-	if first {
-		token := peek_token(parser)
-		if token == nil {
-			return false
-		}
-		parser.marks = append(parser.marks, token.start_mark)
-		skip_token(parser)
-	}
-
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	if token.typ == yaml_BLOCK_ENTRY_TOKEN {
-		mark := token.end_mark
-		prior_head_len := len(parser.head_comment)
-		skip_token(parser)
-		yaml_parser_split_stem_comment(parser, prior_head_len)
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {
-			parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
-			return yaml_parser_parse_node(parser, event, true, false)
-		} else {
-			parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
-			return yaml_parser_process_empty_scalar(parser, event, mark)
-		}
-	}
-	if token.typ == yaml_BLOCK_END_TOKEN {
-		parser.state = parser.states[len(parser.states)-1]
-		parser.states = parser.states[:len(parser.states)-1]
-		parser.marks = parser.marks[:len(parser.marks)-1]
-
-		*event = yaml_event_t{
-			typ:        yaml_SEQUENCE_END_EVENT,
-			start_mark: token.start_mark,
-			end_mark:   token.end_mark,
-		}
-
-		skip_token(parser)
-		return true
-	}
-
-	context_mark := parser.marks[len(parser.marks)-1]
-	parser.marks = parser.marks[:len(parser.marks)-1]
-	return yaml_parser_set_parser_error_context(parser,
-		"while parsing a block collection", context_mark,
-		"did not find expected '-' indicator", token.start_mark)
-}
-
-// Parse the productions:
-// indentless_sequence  ::= (BLOCK-ENTRY block_node?)+
-//
-//	*********** *
-func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	if token.typ == yaml_BLOCK_ENTRY_TOKEN {
-		mark := token.end_mark
-		prior_head_len := len(parser.head_comment)
-		skip_token(parser)
-		yaml_parser_split_stem_comment(parser, prior_head_len)
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ != yaml_BLOCK_ENTRY_TOKEN &&
-			token.typ != yaml_KEY_TOKEN &&
-			token.typ != yaml_VALUE_TOKEN &&
-			token.typ != yaml_BLOCK_END_TOKEN {
-			parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)
-			return yaml_parser_parse_node(parser, event, true, false)
-		}
-		parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
-		return yaml_parser_process_empty_scalar(parser, event, mark)
-	}
-	parser.state = parser.states[len(parser.states)-1]
-	parser.states = parser.states[:len(parser.states)-1]
-
-	*event = yaml_event_t{
-		typ:        yaml_SEQUENCE_END_EVENT,
-		start_mark: token.start_mark,
-		end_mark:   token.start_mark, // [Go] Shouldn't this be token.end_mark?
-	}
-	return true
-}
-
-// Split stem comment from head comment.
-//
-// When a sequence or map is found under a sequence entry, the former head comment
-// is assigned to the underlying sequence or map as a whole, not the individual
-// sequence or map entry as would be expected otherwise. To handle this case the
-// previous head comment is moved aside as the stem comment.
-func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
-	if stem_len == 0 {
-		return
-	}
-
-	token := peek_token(parser)
-	if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
-		return
-	}
-
-	parser.stem_comment = parser.head_comment[:stem_len]
-	if len(parser.head_comment) == stem_len {
-		parser.head_comment = nil
-	} else {
-		// Copy suffix to prevent very strange bugs if someone ever appends
-		// further bytes to the prefix in the stem_comment slice above.
-		parser.head_comment = append([]byte(nil), parser.head_comment[stem_len+1:]...)
-	}
-}
-
-// Parse the productions:
-// block_mapping        ::= BLOCK-MAPPING_START
-//
-//	*******************
-//	((KEY block_node_or_indentless_sequence?)?
-//	  *** *
-//	(VALUE block_node_or_indentless_sequence?)?)*
-//
-//	BLOCK-END
-//	*********
-func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
-	if first {
-		token := peek_token(parser)
-		if token == nil {
-			return false
-		}
-		parser.marks = append(parser.marks, token.start_mark)
-		skip_token(parser)
-	}
-
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	// [Go] A tail comment was left from the prior mapping value processed. Emit an event
-	//      as it needs to be processed with that value and not the following key.
-	if len(parser.tail_comment) > 0 {
-		*event = yaml_event_t{
-			typ:          yaml_TAIL_COMMENT_EVENT,
-			start_mark:   token.start_mark,
-			end_mark:     token.end_mark,
-			foot_comment: parser.tail_comment,
-		}
-		parser.tail_comment = nil
-		return true
-	}
-
-	if token.typ == yaml_KEY_TOKEN {
-		mark := token.end_mark
-		skip_token(parser)
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ != yaml_KEY_TOKEN &&
-			token.typ != yaml_VALUE_TOKEN &&
-			token.typ != yaml_BLOCK_END_TOKEN {
-			parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)
-			return yaml_parser_parse_node(parser, event, true, true)
-		} else {
-			parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
-			return yaml_parser_process_empty_scalar(parser, event, mark)
-		}
-	} else if token.typ == yaml_BLOCK_END_TOKEN {
-		parser.state = parser.states[len(parser.states)-1]
-		parser.states = parser.states[:len(parser.states)-1]
-		parser.marks = parser.marks[:len(parser.marks)-1]
-		*event = yaml_event_t{
-			typ:        yaml_MAPPING_END_EVENT,
-			start_mark: token.start_mark,
-			end_mark:   token.end_mark,
-		}
-		yaml_parser_set_event_comments(parser, event)
-		skip_token(parser)
-		return true
-	}
-
-	context_mark := parser.marks[len(parser.marks)-1]
-	parser.marks = parser.marks[:len(parser.marks)-1]
-	return yaml_parser_set_parser_error_context(parser,
-		"while parsing a block mapping", context_mark,
-		"did not find expected key", token.start_mark)
-}
-
-// Parse the productions:
-// block_mapping        ::= BLOCK-MAPPING_START
-//
-//	((KEY block_node_or_indentless_sequence?)?
-//
-//	(VALUE block_node_or_indentless_sequence?)?)*
-//	 ***** *
-//	BLOCK-END
-func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-	if token.typ == yaml_VALUE_TOKEN {
-		mark := token.end_mark
-		skip_token(parser)
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ != yaml_KEY_TOKEN &&
-			token.typ != yaml_VALUE_TOKEN &&
-			token.typ != yaml_BLOCK_END_TOKEN {
-			parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)
-			return yaml_parser_parse_node(parser, event, true, true)
-		}
-		parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
-		return yaml_parser_process_empty_scalar(parser, event, mark)
-	}
-	parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
-	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Parse the productions:
-// flow_sequence        ::= FLOW-SEQUENCE-START
-//
-//	*******************
-//	(flow_sequence_entry FLOW-ENTRY)*
-//	 *                   **********
-//	flow_sequence_entry?
-//	*
-//	FLOW-SEQUENCE-END
-//	*****************
-//
-// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//
-//	*
-func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
-	if first {
-		token := peek_token(parser)
-		if token == nil {
-			return false
-		}
-		parser.marks = append(parser.marks, token.start_mark)
-		skip_token(parser)
-	}
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-	if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
-		if !first {
-			if token.typ == yaml_FLOW_ENTRY_TOKEN {
-				skip_token(parser)
-				token = peek_token(parser)
-				if token == nil {
-					return false
-				}
-			} else {
-				context_mark := parser.marks[len(parser.marks)-1]
-				parser.marks = parser.marks[:len(parser.marks)-1]
-				return yaml_parser_set_parser_error_context(parser,
-					"while parsing a flow sequence", context_mark,
-					"did not find expected ',' or ']'", token.start_mark)
-			}
-		}
-
-		if token.typ == yaml_KEY_TOKEN {
-			parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
-			*event = yaml_event_t{
-				typ:        yaml_MAPPING_START_EVENT,
-				start_mark: token.start_mark,
-				end_mark:   token.end_mark,
-				implicit:   true,
-				style:      yaml_style_t(yaml_FLOW_MAPPING_STYLE),
-			}
-			skip_token(parser)
-			return true
-		} else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
-			parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)
-			return yaml_parser_parse_node(parser, event, false, false)
-		}
-	}
-
-	parser.state = parser.states[len(parser.states)-1]
-	parser.states = parser.states[:len(parser.states)-1]
-	parser.marks = parser.marks[:len(parser.marks)-1]
-
-	*event = yaml_event_t{
-		typ:        yaml_SEQUENCE_END_EVENT,
-		start_mark: token.start_mark,
-		end_mark:   token.end_mark,
-	}
-	yaml_parser_set_event_comments(parser, event)
-
-	skip_token(parser)
-	return true
-}
-
-// Parse the productions:
-// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//
-//	*** *
-func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-	if token.typ != yaml_VALUE_TOKEN &&
-		token.typ != yaml_FLOW_ENTRY_TOKEN &&
-		token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
-		parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)
-		return yaml_parser_parse_node(parser, event, false, false)
-	}
-	mark := token.end_mark
-	skip_token(parser)
-	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
-	return yaml_parser_process_empty_scalar(parser, event, mark)
-}
-
-// Parse the productions:
-// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//
-//	***** *
-func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-	if token.typ == yaml_VALUE_TOKEN {
-		skip_token(parser)
-		token := peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
-			parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)
-			return yaml_parser_parse_node(parser, event, false, false)
-		}
-	}
-	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
-	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Parse the productions:
-// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//
-//	*
-func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
-	*event = yaml_event_t{
-		typ:        yaml_MAPPING_END_EVENT,
-		start_mark: token.start_mark,
-		end_mark:   token.start_mark, // [Go] Shouldn't this be end_mark?
-	}
-	return true
-}
-
-// Parse the productions:
-// flow_mapping         ::= FLOW-MAPPING-START
-//
-//	******************
-//	(flow_mapping_entry FLOW-ENTRY)*
-//	 *                  **********
-//	flow_mapping_entry?
-//	******************
-//	FLOW-MAPPING-END
-//	****************
-//
-// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//   - *** *
-func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
-	if first {
-		token := peek_token(parser)
-		parser.marks = append(parser.marks, token.start_mark)
-		skip_token(parser)
-	}
-
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
-		if !first {
-			if token.typ == yaml_FLOW_ENTRY_TOKEN {
-				skip_token(parser)
-				token = peek_token(parser)
-				if token == nil {
-					return false
-				}
-			} else {
-				context_mark := parser.marks[len(parser.marks)-1]
-				parser.marks = parser.marks[:len(parser.marks)-1]
-				return yaml_parser_set_parser_error_context(parser,
-					"while parsing a flow mapping", context_mark,
-					"did not find expected ',' or '}'", token.start_mark)
-			}
-		}
-
-		if token.typ == yaml_KEY_TOKEN {
-			skip_token(parser)
-			token = peek_token(parser)
-			if token == nil {
-				return false
-			}
-			if token.typ != yaml_VALUE_TOKEN &&
-				token.typ != yaml_FLOW_ENTRY_TOKEN &&
-				token.typ != yaml_FLOW_MAPPING_END_TOKEN {
-				parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)
-				return yaml_parser_parse_node(parser, event, false, false)
-			} else {
-				parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE
-				return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-			}
-		} else if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
-			parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)
-			return yaml_parser_parse_node(parser, event, false, false)
-		}
-	}
-
-	parser.state = parser.states[len(parser.states)-1]
-	parser.states = parser.states[:len(parser.states)-1]
-	parser.marks = parser.marks[:len(parser.marks)-1]
-	*event = yaml_event_t{
-		typ:        yaml_MAPPING_END_EVENT,
-		start_mark: token.start_mark,
-		end_mark:   token.end_mark,
-	}
-	yaml_parser_set_event_comments(parser, event)
-	skip_token(parser)
-	return true
-}
-
-// Parse the productions:
-// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-//   - ***** *
-func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-	if empty {
-		parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
-		return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-	}
-	if token.typ == yaml_VALUE_TOKEN {
-		skip_token(parser)
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-		if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN {
-			parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)
-			return yaml_parser_parse_node(parser, event, false, false)
-		}
-	}
-	parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
-	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Generate an empty scalar event.
-func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool {
-	*event = yaml_event_t{
-		typ:        yaml_SCALAR_EVENT,
-		start_mark: mark,
-		end_mark:   mark,
-		value:      nil, // Empty
-		implicit:   true,
-		style:      yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
-	}
-	return true
-}
-
-var default_tag_directives = []yaml_tag_directive_t{
-	{[]byte("!"), []byte("!")},
-	{[]byte("!!"), []byte("tag:yaml.org,2002:")},
-}
-
-// Parse directives.
-func yaml_parser_process_directives(parser *yaml_parser_t,
-	version_directive_ref **yaml_version_directive_t,
-	tag_directives_ref *[]yaml_tag_directive_t) bool {
-
-	var version_directive *yaml_version_directive_t
-	var tag_directives []yaml_tag_directive_t
-
-	token := peek_token(parser)
-	if token == nil {
-		return false
-	}
-
-	for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN {
-		if token.typ == yaml_VERSION_DIRECTIVE_TOKEN {
-			if version_directive != nil {
-				yaml_parser_set_parser_error(parser,
-					"found duplicate %YAML directive", token.start_mark)
-				return false
-			}
-			if token.major != 1 || token.minor != 1 {
-				yaml_parser_set_parser_error(parser,
-					"found incompatible YAML document", token.start_mark)
-				return false
-			}
-			version_directive = &yaml_version_directive_t{
-				major: token.major,
-				minor: token.minor,
-			}
-		} else if token.typ == yaml_TAG_DIRECTIVE_TOKEN {
-			value := yaml_tag_directive_t{
-				handle: token.value,
-				prefix: token.prefix,
-			}
-			if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) {
-				return false
-			}
-			tag_directives = append(tag_directives, value)
-		}
-
-		skip_token(parser)
-		token = peek_token(parser)
-		if token == nil {
-			return false
-		}
-	}
-
-	for i := range default_tag_directives {
-		if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {
-			return false
-		}
-	}
-
-	if version_directive_ref != nil {
-		*version_directive_ref = version_directive
-	}
-	if tag_directives_ref != nil {
-		*tag_directives_ref = tag_directives
-	}
-	return true
-}
-
-// Append a tag directive to the directives stack.
-func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool {
-	for i := range parser.tag_directives {
-		if bytes.Equal(value.handle, parser.tag_directives[i].handle) {
-			if allow_duplicates {
-				return true
-			}
-			return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)
-		}
-	}
-
-	// [Go] I suspect the copy is unnecessary. This was likely done
-	// because there was no way to track ownership of the data.
-	value_copy := yaml_tag_directive_t{
-		handle: make([]byte, len(value.handle)),
-		prefix: make([]byte, len(value.prefix)),
-	}
-	copy(value_copy.handle, value.handle)
-	copy(value_copy.prefix, value.prefix)
-	parser.tag_directives = append(parser.tag_directives, value_copy)
-	return true
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/readerc.go
@@ -1,434 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
-	"io"
-)
-
-// Set the reader error and return 0.
-func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
-	parser.error = yaml_READER_ERROR
-	parser.problem = problem
-	parser.problem_offset = offset
-	parser.problem_value = value
-	return false
-}
-
-// Byte order marks.
-const (
-	bom_UTF8    = "\xef\xbb\xbf"
-	bom_UTF16LE = "\xff\xfe"
-	bom_UTF16BE = "\xfe\xff"
-)
-
-// Determine the input stream encoding by checking the BOM symbol. If no BOM is
-// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
-func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
-	// Ensure that we had enough bytes in the raw buffer.
-	for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
-		if !yaml_parser_update_raw_buffer(parser) {
-			return false
-		}
-	}
-
-	// Determine the encoding.
-	buf := parser.raw_buffer
-	pos := parser.raw_buffer_pos
-	avail := len(buf) - pos
-	if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
-		parser.encoding = yaml_UTF16LE_ENCODING
-		parser.raw_buffer_pos += 2
-		parser.offset += 2
-	} else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
-		parser.encoding = yaml_UTF16BE_ENCODING
-		parser.raw_buffer_pos += 2
-		parser.offset += 2
-	} else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
-		parser.encoding = yaml_UTF8_ENCODING
-		parser.raw_buffer_pos += 3
-		parser.offset += 3
-	} else {
-		parser.encoding = yaml_UTF8_ENCODING
-	}
-	return true
-}
-
-// Update the raw buffer.
-func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
-	size_read := 0
-
-	// Return if the raw buffer is full.
-	if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
-		return true
-	}
-
-	// Return on EOF.
-	if parser.eof {
-		return true
-	}
-
-	// Move the remaining bytes in the raw buffer to the beginning.
-	if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
-		copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
-	}
-	parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
-	parser.raw_buffer_pos = 0
-
-	// Call the read handler to fill the buffer.
-	size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
-	parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
-	if err == io.EOF {
-		parser.eof = true
-	} else if err != nil {
-		return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
-	}
-	return true
-}
-
-// Ensure that the buffer contains at least `length` characters.
-// Return true on success, false on failure.
-//
-// The length is supposed to be significantly less that the buffer size.
-func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
-	if parser.read_handler == nil {
-		panic("read handler must be set")
-	}
-
-	// [Go] This function was changed to guarantee the requested length size at EOF.
-	// The fact we need to do this is pretty awful, but the description above implies
-	// for that to be the case, and there are tests
-
-	// If the EOF flag is set and the raw buffer is empty, do nothing.
-	if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
-		// [Go] ACTUALLY! Read the documentation of this function above.
-		// This is just broken. To return true, we need to have the
-		// given length in the buffer. Not doing that means every single
-		// check that calls this function to make sure the buffer has a
-		// given length is Go) panicking; or C) accessing invalid memory.
-		//return true
-	}
-
-	// Return if the buffer contains enough characters.
-	if parser.unread >= length {
-		return true
-	}
-
-	// Determine the input encoding if it is not known yet.
-	if parser.encoding == yaml_ANY_ENCODING {
-		if !yaml_parser_determine_encoding(parser) {
-			return false
-		}
-	}
-
-	// Move the unread characters to the beginning of the buffer.
-	buffer_len := len(parser.buffer)
-	if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
-		copy(parser.buffer, parser.buffer[parser.buffer_pos:])
-		buffer_len -= parser.buffer_pos
-		parser.buffer_pos = 0
-	} else if parser.buffer_pos == buffer_len {
-		buffer_len = 0
-		parser.buffer_pos = 0
-	}
-
-	// Open the whole buffer for writing, and cut it before returning.
-	parser.buffer = parser.buffer[:cap(parser.buffer)]
-
-	// Fill the buffer until it has enough characters.
-	first := true
-	for parser.unread < length {
-
-		// Fill the raw buffer if necessary.
-		if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
-			if !yaml_parser_update_raw_buffer(parser) {
-				parser.buffer = parser.buffer[:buffer_len]
-				return false
-			}
-		}
-		first = false
-
-		// Decode the raw buffer.
-	inner:
-		for parser.raw_buffer_pos != len(parser.raw_buffer) {
-			var value rune
-			var width int
-
-			raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
-
-			// Decode the next character.
-			switch parser.encoding {
-			case yaml_UTF8_ENCODING:
-				// Decode a UTF-8 character.  Check RFC 3629
-				// (http://www.ietf.org/rfc/rfc3629.txt) for more details.
-				//
-				// The following table (taken from the RFC) is used for
-				// decoding.
-				//
-				//    Char. number range |        UTF-8 octet sequence
-				//      (hexadecimal)    |              (binary)
-				//   --------------------+------------------------------------
-				//   0000 0000-0000 007F | 0xxxxxxx
-				//   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
-				//   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
-				//   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-				//
-				// Additionally, the characters in the range 0xD800-0xDFFF
-				// are prohibited as they are reserved for use with UTF-16
-				// surrogate pairs.
-
-				// Determine the length of the UTF-8 sequence.
-				octet := parser.raw_buffer[parser.raw_buffer_pos]
-				switch {
-				case octet&0x80 == 0x00:
-					width = 1
-				case octet&0xE0 == 0xC0:
-					width = 2
-				case octet&0xF0 == 0xE0:
-					width = 3
-				case octet&0xF8 == 0xF0:
-					width = 4
-				default:
-					// The leading octet is invalid.
-					return yaml_parser_set_reader_error(parser,
-						"invalid leading UTF-8 octet",
-						parser.offset, int(octet))
-				}
-
-				// Check if the raw buffer contains an incomplete character.
-				if width > raw_unread {
-					if parser.eof {
-						return yaml_parser_set_reader_error(parser,
-							"incomplete UTF-8 octet sequence",
-							parser.offset, -1)
-					}
-					break inner
-				}
-
-				// Decode the leading octet.
-				switch {
-				case octet&0x80 == 0x00:
-					value = rune(octet & 0x7F)
-				case octet&0xE0 == 0xC0:
-					value = rune(octet & 0x1F)
-				case octet&0xF0 == 0xE0:
-					value = rune(octet & 0x0F)
-				case octet&0xF8 == 0xF0:
-					value = rune(octet & 0x07)
-				default:
-					value = 0
-				}
-
-				// Check and decode the trailing octets.
-				for k := 1; k < width; k++ {
-					octet = parser.raw_buffer[parser.raw_buffer_pos+k]
-
-					// Check if the octet is valid.
-					if (octet & 0xC0) != 0x80 {
-						return yaml_parser_set_reader_error(parser,
-							"invalid trailing UTF-8 octet",
-							parser.offset+k, int(octet))
-					}
-
-					// Decode the octet.
-					value = (value << 6) + rune(octet&0x3F)
-				}
-
-				// Check the length of the sequence against the value.
-				switch {
-				case width == 1:
-				case width == 2 && value >= 0x80:
-				case width == 3 && value >= 0x800:
-				case width == 4 && value >= 0x10000:
-				default:
-					return yaml_parser_set_reader_error(parser,
-						"invalid length of a UTF-8 sequence",
-						parser.offset, -1)
-				}
-
-				// Check the range of the value.
-				if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
-					return yaml_parser_set_reader_error(parser,
-						"invalid Unicode character",
-						parser.offset, int(value))
-				}
-
-			case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
-				var low, high int
-				if parser.encoding == yaml_UTF16LE_ENCODING {
-					low, high = 0, 1
-				} else {
-					low, high = 1, 0
-				}
-
-				// The UTF-16 encoding is not as simple as one might
-				// naively think.  Check RFC 2781
-				// (http://www.ietf.org/rfc/rfc2781.txt).
-				//
-				// Normally, two subsequent bytes describe a Unicode
-				// character.  However a special technique (called a
-				// surrogate pair) is used for specifying character
-				// values larger than 0xFFFF.
-				//
-				// A surrogate pair consists of two pseudo-characters:
-				//      high surrogate area (0xD800-0xDBFF)
-				//      low surrogate area (0xDC00-0xDFFF)
-				//
-				// The following formulas are used for decoding
-				// and encoding characters using surrogate pairs:
-				//
-				//  U  = U' + 0x10000   (0x01 00 00 <= U <= 0x10 FF FF)
-				//  U' = yyyyyyyyyyxxxxxxxxxx   (0 <= U' <= 0x0F FF FF)
-				//  W1 = 110110yyyyyyyyyy
-				//  W2 = 110111xxxxxxxxxx
-				//
-				// where U is the character value, W1 is the high surrogate
-				// area, W2 is the low surrogate area.
-
-				// Check for incomplete UTF-16 character.
-				if raw_unread < 2 {
-					if parser.eof {
-						return yaml_parser_set_reader_error(parser,
-							"incomplete UTF-16 character",
-							parser.offset, -1)
-					}
-					break inner
-				}
-
-				// Get the character.
-				value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
-					(rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
-
-				// Check for unexpected low surrogate area.
-				if value&0xFC00 == 0xDC00 {
-					return yaml_parser_set_reader_error(parser,
-						"unexpected low surrogate area",
-						parser.offset, int(value))
-				}
-
-				// Check for a high surrogate area.
-				if value&0xFC00 == 0xD800 {
-					width = 4
-
-					// Check for incomplete surrogate pair.
-					if raw_unread < 4 {
-						if parser.eof {
-							return yaml_parser_set_reader_error(parser,
-								"incomplete UTF-16 surrogate pair",
-								parser.offset, -1)
-						}
-						break inner
-					}
-
-					// Get the next character.
-					value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
-						(rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
-
-					// Check for a low surrogate area.
-					if value2&0xFC00 != 0xDC00 {
-						return yaml_parser_set_reader_error(parser,
-							"expected low surrogate area",
-							parser.offset+2, int(value2))
-					}
-
-					// Generate the value of the surrogate pair.
-					value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
-				} else {
-					width = 2
-				}
-
-			default:
-				panic("impossible")
-			}
-
-			// Check if the character is in the allowed range:
-			//      #x9 | #xA | #xD | [#x20-#x7E]               (8 bit)
-			//      | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD]    (16 bit)
-			//      | [#x10000-#x10FFFF]                        (32 bit)
-			switch {
-			case value == 0x09:
-			case value == 0x0A:
-			case value == 0x0D:
-			case value >= 0x20 && value <= 0x7E:
-			case value == 0x85:
-			case value >= 0xA0 && value <= 0xD7FF:
-			case value >= 0xE000 && value <= 0xFFFD:
-			case value >= 0x10000 && value <= 0x10FFFF:
-			default:
-				return yaml_parser_set_reader_error(parser,
-					"control characters are not allowed",
-					parser.offset, int(value))
-			}
-
-			// Move the raw pointers.
-			parser.raw_buffer_pos += width
-			parser.offset += width
-
-			// Finally put the character into the buffer.
-			if value <= 0x7F {
-				// 0000 0000-0000 007F . 0xxxxxxx
-				parser.buffer[buffer_len+0] = byte(value)
-				buffer_len += 1
-			} else if value <= 0x7FF {
-				// 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
-				parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
-				parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
-				buffer_len += 2
-			} else if value <= 0xFFFF {
-				// 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
-				parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
-				parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
-				parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
-				buffer_len += 3
-			} else {
-				// 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-				parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
-				parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
-				parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
-				parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
-				buffer_len += 4
-			}
-
-			parser.unread++
-		}
-
-		// On EOF, put NUL into the buffer and return.
-		if parser.eof {
-			parser.buffer[buffer_len] = 0
-			buffer_len++
-			parser.unread++
-			break
-		}
-	}
-	// [Go] Read the documentation of this function above. To return true,
-	// we need to have the given length in the buffer. Not doing that means
-	// every single check that calls this function to make sure the buffer
-	// has a given length is Go) panicking; or C) accessing invalid memory.
-	// This happens here due to the EOF above breaking early.
-	for buffer_len < length {
-		parser.buffer[buffer_len] = 0
-		buffer_len++
-	}
-	parser.buffer = parser.buffer[:buffer_len]
-	return true
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/README.md
@@ -1,150 +0,0 @@
-# YAML support for the Go language
-
-Introduction
-------------
-
-The yaml package enables Go programs to comfortably encode and decode YAML
-values. It was developed within [Canonical](https://www.canonical.com) as
-part of the [juju](https://juju.ubuntu.com) project, and is based on a
-pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
-C library to parse and generate YAML data quickly and reliably.
-
-Compatibility
--------------
-
-The yaml package supports most of YAML 1.2, but preserves some behavior
-from 1.1 for backwards compatibility.
-
-Specifically, as of v3 of the yaml package:
-
- - YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being
-   decoded into a typed bool value. Otherwise they behave as a string. Booleans
-   in YAML 1.2 are _true/false_ only.
- - Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_
-   as specified in YAML 1.2, because most parsers still use the old format.
-   Octals in the  _0o777_ format are supported though, so new files work.
- - Does not support base-60 floats. These are gone from YAML 1.2, and were
-   actually never supported by this package as it's clearly a poor choice.
-
-and offers backwards
-compatibility with YAML 1.1 in some cases.
-1.2, including support for
-anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
-implemented, and base-60 floats from YAML 1.1 are purposefully not
-supported since they're a poor design and are gone in YAML 1.2.
-
-Installation and usage
-----------------------
-
-The import path for the package is *gopkg.in/yaml.v3*.
-
-To install it, run:
-
-    go get gopkg.in/yaml.v3
-
-API documentation
------------------
-
-If opened in a browser, the import path itself leads to the API documentation:
-
-  - [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3)
-
-API stability
--------------
-
-The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in).
-
-
-License
--------
-
-The yaml package is licensed under the MIT and Apache License 2.0 licenses.
-Please see the LICENSE file for details.
-
-
-Example
--------
-
-```Go
-package main
-
-import (
-        "fmt"
-        "log"
-
-        "gopkg.in/yaml.v3"
-)
-
-var data = `
-a: Easy!
-b:
-  c: 2
-  d: [3, 4]
-`
-
-// Note: struct fields must be public in order for unmarshal to
-// correctly populate the data.
-type T struct {
-        A string
-        B struct {
-                RenamedC int   `yaml:"c"`
-                D        []int `yaml:",flow"`
-        }
-}
-
-func main() {
-        t := T{}
-    
-        err := yaml.Unmarshal([]byte(data), &t)
-        if err != nil {
-                log.Fatalf("error: %v", err)
-        }
-        fmt.Printf("--- t:\n%v\n\n", t)
-    
-        d, err := yaml.Marshal(&t)
-        if err != nil {
-                log.Fatalf("error: %v", err)
-        }
-        fmt.Printf("--- t dump:\n%s\n\n", string(d))
-    
-        m := make(map[interface{}]interface{})
-    
-        err = yaml.Unmarshal([]byte(data), &m)
-        if err != nil {
-                log.Fatalf("error: %v", err)
-        }
-        fmt.Printf("--- m:\n%v\n\n", m)
-    
-        d, err = yaml.Marshal(&m)
-        if err != nil {
-                log.Fatalf("error: %v", err)
-        }
-        fmt.Printf("--- m dump:\n%s\n\n", string(d))
-}
-```
-
-This example will generate the following output:
-
-```
---- t:
-{Easy! {2 [3 4]}}
-
---- t dump:
-a: Easy!
-b:
-  c: 2
-  d: [3, 4]
-
-
---- m:
-map[a:Easy! b:map[c:2 d:[3 4]]]
-
---- m dump:
-a: Easy!
-b:
-  c: 2
-  d:
-  - 3
-  - 4
-```
-
tools/review-tool/vendor/gopkg.in/yaml.v3/resolve.go
@@ -1,326 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package yaml
-
-import (
-	"encoding/base64"
-	"math"
-	"regexp"
-	"strconv"
-	"strings"
-	"time"
-)
-
-type resolveMapItem struct {
-	value interface{}
-	tag   string
-}
-
-var resolveTable = make([]byte, 256)
-var resolveMap = make(map[string]resolveMapItem)
-
-func init() {
-	t := resolveTable
-	t[int('+')] = 'S' // Sign
-	t[int('-')] = 'S'
-	for _, c := range "0123456789" {
-		t[int(c)] = 'D' // Digit
-	}
-	for _, c := range "yYnNtTfFoO~" {
-		t[int(c)] = 'M' // In map
-	}
-	t[int('.')] = '.' // Float (potentially in map)
-
-	var resolveMapList = []struct {
-		v   interface{}
-		tag string
-		l   []string
-	}{
-		{true, boolTag, []string{"true", "True", "TRUE"}},
-		{false, boolTag, []string{"false", "False", "FALSE"}},
-		{nil, nullTag, []string{"", "~", "null", "Null", "NULL"}},
-		{math.NaN(), floatTag, []string{".nan", ".NaN", ".NAN"}},
-		{math.Inf(+1), floatTag, []string{".inf", ".Inf", ".INF"}},
-		{math.Inf(+1), floatTag, []string{"+.inf", "+.Inf", "+.INF"}},
-		{math.Inf(-1), floatTag, []string{"-.inf", "-.Inf", "-.INF"}},
-		{"<<", mergeTag, []string{"<<"}},
-	}
-
-	m := resolveMap
-	for _, item := range resolveMapList {
-		for _, s := range item.l {
-			m[s] = resolveMapItem{item.v, item.tag}
-		}
-	}
-}
-
-const (
-	nullTag      = "!!null"
-	boolTag      = "!!bool"
-	strTag       = "!!str"
-	intTag       = "!!int"
-	floatTag     = "!!float"
-	timestampTag = "!!timestamp"
-	seqTag       = "!!seq"
-	mapTag       = "!!map"
-	binaryTag    = "!!binary"
-	mergeTag     = "!!merge"
-)
-
-var longTags = make(map[string]string)
-var shortTags = make(map[string]string)
-
-func init() {
-	for _, stag := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} {
-		ltag := longTag(stag)
-		longTags[stag] = ltag
-		shortTags[ltag] = stag
-	}
-}
-
-const longTagPrefix = "tag:yaml.org,2002:"
-
-func shortTag(tag string) string {
-	if strings.HasPrefix(tag, longTagPrefix) {
-		if stag, ok := shortTags[tag]; ok {
-			return stag
-		}
-		return "!!" + tag[len(longTagPrefix):]
-	}
-	return tag
-}
-
-func longTag(tag string) string {
-	if strings.HasPrefix(tag, "!!") {
-		if ltag, ok := longTags[tag]; ok {
-			return ltag
-		}
-		return longTagPrefix + tag[2:]
-	}
-	return tag
-}
-
-func resolvableTag(tag string) bool {
-	switch tag {
-	case "", strTag, boolTag, intTag, floatTag, nullTag, timestampTag:
-		return true
-	}
-	return false
-}
-
-var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
-
-func resolve(tag string, in string) (rtag string, out interface{}) {
-	tag = shortTag(tag)
-	if !resolvableTag(tag) {
-		return tag, in
-	}
-
-	defer func() {
-		switch tag {
-		case "", rtag, strTag, binaryTag:
-			return
-		case floatTag:
-			if rtag == intTag {
-				switch v := out.(type) {
-				case int64:
-					rtag = floatTag
-					out = float64(v)
-					return
-				case int:
-					rtag = floatTag
-					out = float64(v)
-					return
-				}
-			}
-		}
-		failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
-	}()
-
-	// Any data is accepted as a !!str or !!binary.
-	// Otherwise, the prefix is enough of a hint about what it might be.
-	hint := byte('N')
-	if in != "" {
-		hint = resolveTable[in[0]]
-	}
-	if hint != 0 && tag != strTag && tag != binaryTag {
-		// Handle things we can lookup in a map.
-		if item, ok := resolveMap[in]; ok {
-			return item.tag, item.value
-		}
-
-		// Base 60 floats are a bad idea, were dropped in YAML 1.2, and
-		// are purposefully unsupported here. They're still quoted on
-		// the way out for compatibility with other parser, though.
-
-		switch hint {
-		case 'M':
-			// We've already checked the map above.
-
-		case '.':
-			// Not in the map, so maybe a normal float.
-			floatv, err := strconv.ParseFloat(in, 64)
-			if err == nil {
-				return floatTag, floatv
-			}
-
-		case 'D', 'S':
-			// Int, float, or timestamp.
-			// Only try values as a timestamp if the value is unquoted or there's an explicit
-			// !!timestamp tag.
-			if tag == "" || tag == timestampTag {
-				t, ok := parseTimestamp(in)
-				if ok {
-					return timestampTag, t
-				}
-			}
-
-			plain := strings.Replace(in, "_", "", -1)
-			intv, err := strconv.ParseInt(plain, 0, 64)
-			if err == nil {
-				if intv == int64(int(intv)) {
-					return intTag, int(intv)
-				} else {
-					return intTag, intv
-				}
-			}
-			uintv, err := strconv.ParseUint(plain, 0, 64)
-			if err == nil {
-				return intTag, uintv
-			}
-			if yamlStyleFloat.MatchString(plain) {
-				floatv, err := strconv.ParseFloat(plain, 64)
-				if err == nil {
-					return floatTag, floatv
-				}
-			}
-			if strings.HasPrefix(plain, "0b") {
-				intv, err := strconv.ParseInt(plain[2:], 2, 64)
-				if err == nil {
-					if intv == int64(int(intv)) {
-						return intTag, int(intv)
-					} else {
-						return intTag, intv
-					}
-				}
-				uintv, err := strconv.ParseUint(plain[2:], 2, 64)
-				if err == nil {
-					return intTag, uintv
-				}
-			} else if strings.HasPrefix(plain, "-0b") {
-				intv, err := strconv.ParseInt("-"+plain[3:], 2, 64)
-				if err == nil {
-					if true || intv == int64(int(intv)) {
-						return intTag, int(intv)
-					} else {
-						return intTag, intv
-					}
-				}
-			}
-			// Octals as introduced in version 1.2 of the spec.
-			// Octals from the 1.1 spec, spelled as 0777, are still
-			// decoded by default in v3 as well for compatibility.
-			// May be dropped in v4 depending on how usage evolves.
-			if strings.HasPrefix(plain, "0o") {
-				intv, err := strconv.ParseInt(plain[2:], 8, 64)
-				if err == nil {
-					if intv == int64(int(intv)) {
-						return intTag, int(intv)
-					} else {
-						return intTag, intv
-					}
-				}
-				uintv, err := strconv.ParseUint(plain[2:], 8, 64)
-				if err == nil {
-					return intTag, uintv
-				}
-			} else if strings.HasPrefix(plain, "-0o") {
-				intv, err := strconv.ParseInt("-"+plain[3:], 8, 64)
-				if err == nil {
-					if true || intv == int64(int(intv)) {
-						return intTag, int(intv)
-					} else {
-						return intTag, intv
-					}
-				}
-			}
-		default:
-			panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")")
-		}
-	}
-	return strTag, in
-}
-
-// encodeBase64 encodes s as base64 that is broken up into multiple lines
-// as appropriate for the resulting length.
-func encodeBase64(s string) string {
-	const lineLen = 70
-	encLen := base64.StdEncoding.EncodedLen(len(s))
-	lines := encLen/lineLen + 1
-	buf := make([]byte, encLen*2+lines)
-	in := buf[0:encLen]
-	out := buf[encLen:]
-	base64.StdEncoding.Encode(in, []byte(s))
-	k := 0
-	for i := 0; i < len(in); i += lineLen {
-		j := i + lineLen
-		if j > len(in) {
-			j = len(in)
-		}
-		k += copy(out[k:], in[i:j])
-		if lines > 1 {
-			out[k] = '\n'
-			k++
-		}
-	}
-	return string(out[:k])
-}
-
-// This is a subset of the formats allowed by the regular expression
-// defined at http://yaml.org/type/timestamp.html.
-var allowedTimestampFormats = []string{
-	"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
-	"2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
-	"2006-1-2 15:4:5.999999999",       // space separated with no time zone
-	"2006-1-2",                        // date only
-	// Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
-	// from the set of examples.
-}
-
-// parseTimestamp parses s as a timestamp string and
-// returns the timestamp and reports whether it succeeded.
-// Timestamp formats are defined at http://yaml.org/type/timestamp.html
-func parseTimestamp(s string) (time.Time, bool) {
-	// TODO write code to check all the formats supported by
-	// http://yaml.org/type/timestamp.html instead of using time.Parse.
-
-	// Quick check: all date formats start with YYYY-.
-	i := 0
-	for ; i < len(s); i++ {
-		if c := s[i]; c < '0' || c > '9' {
-			break
-		}
-	}
-	if i != 4 || i == len(s) || s[i] != '-' {
-		return time.Time{}, false
-	}
-	for _, format := range allowedTimestampFormats {
-		if t, err := time.Parse(format, s); err == nil {
-			return t, true
-		}
-	}
-	return time.Time{}, false
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/scannerc.go
@@ -1,3040 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
-	"bytes"
-	"fmt"
-)
-
-// Introduction
-// ************
-//
-// The following notes assume that you are familiar with the YAML specification
-// (http://yaml.org/spec/1.2/spec.html).  We mostly follow it, although in
-// some cases we are less restrictive that it requires.
-//
-// The process of transforming a YAML stream into a sequence of events is
-// divided on two steps: Scanning and Parsing.
-//
-// The Scanner transforms the input stream into a sequence of tokens, while the
-// parser transform the sequence of tokens produced by the Scanner into a
-// sequence of parsing events.
-//
-// The Scanner is rather clever and complicated. The Parser, on the contrary,
-// is a straightforward implementation of a recursive-descendant parser (or,
-// LL(1) parser, as it is usually called).
-//
-// Actually there are two issues of Scanning that might be called "clever", the
-// rest is quite straightforward.  The issues are "block collection start" and
-// "simple keys".  Both issues are explained below in details.
-//
-// Here the Scanning step is explained and implemented.  We start with the list
-// of all the tokens produced by the Scanner together with short descriptions.
-//
-// Now, tokens:
-//
-//      STREAM-START(encoding)          # The stream start.
-//      STREAM-END                      # The stream end.
-//      VERSION-DIRECTIVE(major,minor)  # The '%YAML' directive.
-//      TAG-DIRECTIVE(handle,prefix)    # The '%TAG' directive.
-//      DOCUMENT-START                  # '---'
-//      DOCUMENT-END                    # '...'
-//      BLOCK-SEQUENCE-START            # Indentation increase denoting a block
-//      BLOCK-MAPPING-START             # sequence or a block mapping.
-//      BLOCK-END                       # Indentation decrease.
-//      FLOW-SEQUENCE-START             # '['
-//      FLOW-SEQUENCE-END               # ']'
-//      BLOCK-SEQUENCE-START            # '{'
-//      BLOCK-SEQUENCE-END              # '}'
-//      BLOCK-ENTRY                     # '-'
-//      FLOW-ENTRY                      # ','
-//      KEY                             # '?' or nothing (simple keys).
-//      VALUE                           # ':'
-//      ALIAS(anchor)                   # '*anchor'
-//      ANCHOR(anchor)                  # '&anchor'
-//      TAG(handle,suffix)              # '!handle!suffix'
-//      SCALAR(value,style)             # A scalar.
-//
-// The following two tokens are "virtual" tokens denoting the beginning and the
-// end of the stream:
-//
-//      STREAM-START(encoding)
-//      STREAM-END
-//
-// We pass the information about the input stream encoding with the
-// STREAM-START token.
-//
-// The next two tokens are responsible for tags:
-//
-//      VERSION-DIRECTIVE(major,minor)
-//      TAG-DIRECTIVE(handle,prefix)
-//
-// Example:
-//
-//      %YAML   1.1
-//      %TAG    !   !foo
-//      %TAG    !yaml!  tag:yaml.org,2002:
-//      ---
-//
-// The correspoding sequence of tokens:
-//
-//      STREAM-START(utf-8)
-//      VERSION-DIRECTIVE(1,1)
-//      TAG-DIRECTIVE("!","!foo")
-//      TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
-//      DOCUMENT-START
-//      STREAM-END
-//
-// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
-// line.
-//
-// The document start and end indicators are represented by:
-//
-//      DOCUMENT-START
-//      DOCUMENT-END
-//
-// Note that if a YAML stream contains an implicit document (without '---'
-// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
-// produced.
-//
-// In the following examples, we present whole documents together with the
-// produced tokens.
-//
-//      1. An implicit document:
-//
-//          'a scalar'
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          SCALAR("a scalar",single-quoted)
-//          STREAM-END
-//
-//      2. An explicit document:
-//
-//          ---
-//          'a scalar'
-//          ...
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          DOCUMENT-START
-//          SCALAR("a scalar",single-quoted)
-//          DOCUMENT-END
-//          STREAM-END
-//
-//      3. Several documents in a stream:
-//
-//          'a scalar'
-//          ---
-//          'another scalar'
-//          ---
-//          'yet another scalar'
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          SCALAR("a scalar",single-quoted)
-//          DOCUMENT-START
-//          SCALAR("another scalar",single-quoted)
-//          DOCUMENT-START
-//          SCALAR("yet another scalar",single-quoted)
-//          STREAM-END
-//
-// We have already introduced the SCALAR token above.  The following tokens are
-// used to describe aliases, anchors, tag, and scalars:
-//
-//      ALIAS(anchor)
-//      ANCHOR(anchor)
-//      TAG(handle,suffix)
-//      SCALAR(value,style)
-//
-// The following series of examples illustrate the usage of these tokens:
-//
-//      1. A recursive sequence:
-//
-//          &A [ *A ]
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          ANCHOR("A")
-//          FLOW-SEQUENCE-START
-//          ALIAS("A")
-//          FLOW-SEQUENCE-END
-//          STREAM-END
-//
-//      2. A tagged scalar:
-//
-//          !!float "3.14"  # A good approximation.
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          TAG("!!","float")
-//          SCALAR("3.14",double-quoted)
-//          STREAM-END
-//
-//      3. Various scalar styles:
-//
-//          --- # Implicit empty plain scalars do not produce tokens.
-//          --- a plain scalar
-//          --- 'a single-quoted scalar'
-//          --- "a double-quoted scalar"
-//          --- |-
-//            a literal scalar
-//          --- >-
-//            a folded
-//            scalar
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          DOCUMENT-START
-//          DOCUMENT-START
-//          SCALAR("a plain scalar",plain)
-//          DOCUMENT-START
-//          SCALAR("a single-quoted scalar",single-quoted)
-//          DOCUMENT-START
-//          SCALAR("a double-quoted scalar",double-quoted)
-//          DOCUMENT-START
-//          SCALAR("a literal scalar",literal)
-//          DOCUMENT-START
-//          SCALAR("a folded scalar",folded)
-//          STREAM-END
-//
-// Now it's time to review collection-related tokens. We will start with
-// flow collections:
-//
-//      FLOW-SEQUENCE-START
-//      FLOW-SEQUENCE-END
-//      FLOW-MAPPING-START
-//      FLOW-MAPPING-END
-//      FLOW-ENTRY
-//      KEY
-//      VALUE
-//
-// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
-// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
-// correspondingly.  FLOW-ENTRY represent the ',' indicator.  Finally the
-// indicators '?' and ':', which are used for denoting mapping keys and values,
-// are represented by the KEY and VALUE tokens.
-//
-// The following examples show flow collections:
-//
-//      1. A flow sequence:
-//
-//          [item 1, item 2, item 3]
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          FLOW-SEQUENCE-START
-//          SCALAR("item 1",plain)
-//          FLOW-ENTRY
-//          SCALAR("item 2",plain)
-//          FLOW-ENTRY
-//          SCALAR("item 3",plain)
-//          FLOW-SEQUENCE-END
-//          STREAM-END
-//
-//      2. A flow mapping:
-//
-//          {
-//              a simple key: a value,  # Note that the KEY token is produced.
-//              ? a complex key: another value,
-//          }
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          FLOW-MAPPING-START
-//          KEY
-//          SCALAR("a simple key",plain)
-//          VALUE
-//          SCALAR("a value",plain)
-//          FLOW-ENTRY
-//          KEY
-//          SCALAR("a complex key",plain)
-//          VALUE
-//          SCALAR("another value",plain)
-//          FLOW-ENTRY
-//          FLOW-MAPPING-END
-//          STREAM-END
-//
-// A simple key is a key which is not denoted by the '?' indicator.  Note that
-// the Scanner still produce the KEY token whenever it encounters a simple key.
-//
-// For scanning block collections, the following tokens are used (note that we
-// repeat KEY and VALUE here):
-//
-//      BLOCK-SEQUENCE-START
-//      BLOCK-MAPPING-START
-//      BLOCK-END
-//      BLOCK-ENTRY
-//      KEY
-//      VALUE
-//
-// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
-// increase that precedes a block collection (cf. the INDENT token in Python).
-// The token BLOCK-END denote indentation decrease that ends a block collection
-// (cf. the DEDENT token in Python).  However YAML has some syntax pecularities
-// that makes detections of these tokens more complex.
-//
-// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
-// '-', '?', and ':' correspondingly.
-//
-// The following examples show how the tokens BLOCK-SEQUENCE-START,
-// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
-//
-//      1. Block sequences:
-//
-//          - item 1
-//          - item 2
-//          -
-//            - item 3.1
-//            - item 3.2
-//          -
-//            key 1: value 1
-//            key 2: value 2
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          BLOCK-SEQUENCE-START
-//          BLOCK-ENTRY
-//          SCALAR("item 1",plain)
-//          BLOCK-ENTRY
-//          SCALAR("item 2",plain)
-//          BLOCK-ENTRY
-//          BLOCK-SEQUENCE-START
-//          BLOCK-ENTRY
-//          SCALAR("item 3.1",plain)
-//          BLOCK-ENTRY
-//          SCALAR("item 3.2",plain)
-//          BLOCK-END
-//          BLOCK-ENTRY
-//          BLOCK-MAPPING-START
-//          KEY
-//          SCALAR("key 1",plain)
-//          VALUE
-//          SCALAR("value 1",plain)
-//          KEY
-//          SCALAR("key 2",plain)
-//          VALUE
-//          SCALAR("value 2",plain)
-//          BLOCK-END
-//          BLOCK-END
-//          STREAM-END
-//
-//      2. Block mappings:
-//
-//          a simple key: a value   # The KEY token is produced here.
-//          ? a complex key
-//          : another value
-//          a mapping:
-//            key 1: value 1
-//            key 2: value 2
-//          a sequence:
-//            - item 1
-//            - item 2
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          BLOCK-MAPPING-START
-//          KEY
-//          SCALAR("a simple key",plain)
-//          VALUE
-//          SCALAR("a value",plain)
-//          KEY
-//          SCALAR("a complex key",plain)
-//          VALUE
-//          SCALAR("another value",plain)
-//          KEY
-//          SCALAR("a mapping",plain)
-//          BLOCK-MAPPING-START
-//          KEY
-//          SCALAR("key 1",plain)
-//          VALUE
-//          SCALAR("value 1",plain)
-//          KEY
-//          SCALAR("key 2",plain)
-//          VALUE
-//          SCALAR("value 2",plain)
-//          BLOCK-END
-//          KEY
-//          SCALAR("a sequence",plain)
-//          VALUE
-//          BLOCK-SEQUENCE-START
-//          BLOCK-ENTRY
-//          SCALAR("item 1",plain)
-//          BLOCK-ENTRY
-//          SCALAR("item 2",plain)
-//          BLOCK-END
-//          BLOCK-END
-//          STREAM-END
-//
-// YAML does not always require to start a new block collection from a new
-// line.  If the current line contains only '-', '?', and ':' indicators, a new
-// block collection may start at the current line.  The following examples
-// illustrate this case:
-//
-//      1. Collections in a sequence:
-//
-//          - - item 1
-//            - item 2
-//          - key 1: value 1
-//            key 2: value 2
-//          - ? complex key
-//            : complex value
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          BLOCK-SEQUENCE-START
-//          BLOCK-ENTRY
-//          BLOCK-SEQUENCE-START
-//          BLOCK-ENTRY
-//          SCALAR("item 1",plain)
-//          BLOCK-ENTRY
-//          SCALAR("item 2",plain)
-//          BLOCK-END
-//          BLOCK-ENTRY
-//          BLOCK-MAPPING-START
-//          KEY
-//          SCALAR("key 1",plain)
-//          VALUE
-//          SCALAR("value 1",plain)
-//          KEY
-//          SCALAR("key 2",plain)
-//          VALUE
-//          SCALAR("value 2",plain)
-//          BLOCK-END
-//          BLOCK-ENTRY
-//          BLOCK-MAPPING-START
-//          KEY
-//          SCALAR("complex key")
-//          VALUE
-//          SCALAR("complex value")
-//          BLOCK-END
-//          BLOCK-END
-//          STREAM-END
-//
-//      2. Collections in a mapping:
-//
-//          ? a sequence
-//          : - item 1
-//            - item 2
-//          ? a mapping
-//          : key 1: value 1
-//            key 2: value 2
-//
-//      Tokens:
-//
-//          STREAM-START(utf-8)
-//          BLOCK-MAPPING-START
-//          KEY
-//          SCALAR("a sequence",plain)
-//          VALUE
-//          BLOCK-SEQUENCE-START
-//          BLOCK-ENTRY
-//          SCALAR("item 1",plain)
-//          BLOCK-ENTRY
-//          SCALAR("item 2",plain)
-//          BLOCK-END
-//          KEY
-//          SCALAR("a mapping",plain)
-//          VALUE
-//          BLOCK-MAPPING-START
-//          KEY
-//          SCALAR("key 1",plain)
-//          VALUE
-//          SCALAR("value 1",plain)
-//          KEY
-//          SCALAR("key 2",plain)
-//          VALUE
-//          SCALAR("value 2",plain)
-//          BLOCK-END
-//          BLOCK-END
-//          STREAM-END
-//
-// YAML also permits non-indented sequences if they are included into a block
-// mapping.  In this case, the token BLOCK-SEQUENCE-START is not produced:
-//
-//      key:
-//      - item 1    # BLOCK-SEQUENCE-START is NOT produced here.
-//      - item 2
-//
-// Tokens:
-//
-//      STREAM-START(utf-8)
-//      BLOCK-MAPPING-START
-//      KEY
-//      SCALAR("key",plain)
-//      VALUE
-//      BLOCK-ENTRY
-//      SCALAR("item 1",plain)
-//      BLOCK-ENTRY
-//      SCALAR("item 2",plain)
-//      BLOCK-END
-//
-
-// Ensure that the buffer contains the required number of characters.
-// Return true on success, false on failure (reader error or memory error).
-func cache(parser *yaml_parser_t, length int) bool {
-	// [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B)
-	return parser.unread >= length || yaml_parser_update_buffer(parser, length)
-}
-
-// Advance the buffer pointer.
-func skip(parser *yaml_parser_t) {
-	if !is_blank(parser.buffer, parser.buffer_pos) {
-		parser.newlines = 0
-	}
-	parser.mark.index++
-	parser.mark.column++
-	parser.unread--
-	parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
-}
-
-func skip_line(parser *yaml_parser_t) {
-	if is_crlf(parser.buffer, parser.buffer_pos) {
-		parser.mark.index += 2
-		parser.mark.column = 0
-		parser.mark.line++
-		parser.unread -= 2
-		parser.buffer_pos += 2
-		parser.newlines++
-	} else if is_break(parser.buffer, parser.buffer_pos) {
-		parser.mark.index++
-		parser.mark.column = 0
-		parser.mark.line++
-		parser.unread--
-		parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
-		parser.newlines++
-	}
-}
-
-// Copy a character to a string buffer and advance pointers.
-func read(parser *yaml_parser_t, s []byte) []byte {
-	if !is_blank(parser.buffer, parser.buffer_pos) {
-		parser.newlines = 0
-	}
-	w := width(parser.buffer[parser.buffer_pos])
-	if w == 0 {
-		panic("invalid character sequence")
-	}
-	if len(s) == 0 {
-		s = make([]byte, 0, 32)
-	}
-	if w == 1 && len(s)+w <= cap(s) {
-		s = s[:len(s)+1]
-		s[len(s)-1] = parser.buffer[parser.buffer_pos]
-		parser.buffer_pos++
-	} else {
-		s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...)
-		parser.buffer_pos += w
-	}
-	parser.mark.index++
-	parser.mark.column++
-	parser.unread--
-	return s
-}
-
-// Copy a line break character to a string buffer and advance pointers.
-func read_line(parser *yaml_parser_t, s []byte) []byte {
-	buf := parser.buffer
-	pos := parser.buffer_pos
-	switch {
-	case buf[pos] == '\r' && buf[pos+1] == '\n':
-		// CR LF . LF
-		s = append(s, '\n')
-		parser.buffer_pos += 2
-		parser.mark.index++
-		parser.unread--
-	case buf[pos] == '\r' || buf[pos] == '\n':
-		// CR|LF . LF
-		s = append(s, '\n')
-		parser.buffer_pos += 1
-	case buf[pos] == '\xC2' && buf[pos+1] == '\x85':
-		// NEL . LF
-		s = append(s, '\n')
-		parser.buffer_pos += 2
-	case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):
-		// LS|PS . LS|PS
-		s = append(s, buf[parser.buffer_pos:pos+3]...)
-		parser.buffer_pos += 3
-	default:
-		return s
-	}
-	parser.mark.index++
-	parser.mark.column = 0
-	parser.mark.line++
-	parser.unread--
-	parser.newlines++
-	return s
-}
-
-// Get the next token.
-func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {
-	// Erase the token object.
-	*token = yaml_token_t{} // [Go] Is this necessary?
-
-	// No tokens after STREAM-END or error.
-	if parser.stream_end_produced || parser.error != yaml_NO_ERROR {
-		return true
-	}
-
-	// Ensure that the tokens queue contains enough tokens.
-	if !parser.token_available {
-		if !yaml_parser_fetch_more_tokens(parser) {
-			return false
-		}
-	}
-
-	// Fetch the next token from the queue.
-	*token = parser.tokens[parser.tokens_head]
-	parser.tokens_head++
-	parser.tokens_parsed++
-	parser.token_available = false
-
-	if token.typ == yaml_STREAM_END_TOKEN {
-		parser.stream_end_produced = true
-	}
-	return true
-}
-
-// Set the scanner error and return false.
-func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {
-	parser.error = yaml_SCANNER_ERROR
-	parser.context = context
-	parser.context_mark = context_mark
-	parser.problem = problem
-	parser.problem_mark = parser.mark
-	return false
-}
-
-func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {
-	context := "while parsing a tag"
-	if directive {
-		context = "while parsing a %TAG directive"
-	}
-	return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
-}
-
-func trace(args ...interface{}) func() {
-	pargs := append([]interface{}{"+++"}, args...)
-	fmt.Println(pargs...)
-	pargs = append([]interface{}{"---"}, args...)
-	return func() { fmt.Println(pargs...) }
-}
-
-// Ensure that the tokens queue contains at least one token which can be
-// returned to the Parser.
-func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
-	// While we need more tokens to fetch, do it.
-	for {
-		// [Go] The comment parsing logic requires a lookahead of two tokens
-		// so that foot comments may be parsed in time of associating them
-		// with the tokens that are parsed before them, and also for line
-		// comments to be transformed into head comments in some edge cases.
-		if parser.tokens_head < len(parser.tokens)-2 {
-			// If a potential simple key is at the head position, we need to fetch
-			// the next token to disambiguate it.
-			head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
-			if !ok {
-				break
-			} else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
-				return false
-			} else if !valid {
-				break
-			}
-		}
-		// Fetch the next token.
-		if !yaml_parser_fetch_next_token(parser) {
-			return false
-		}
-	}
-
-	parser.token_available = true
-	return true
-}
-
-// The dispatcher for token fetchers.
-func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) {
-	// Ensure that the buffer is initialized.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-
-	// Check if we just started scanning.  Fetch STREAM-START then.
-	if !parser.stream_start_produced {
-		return yaml_parser_fetch_stream_start(parser)
-	}
-
-	scan_mark := parser.mark
-
-	// Eat whitespaces and comments until we reach the next token.
-	if !yaml_parser_scan_to_next_token(parser) {
-		return false
-	}
-
-	// [Go] While unrolling indents, transform the head comments of prior
-	// indentation levels observed after scan_start into foot comments at
-	// the respective indexes.
-
-	// Check the indentation level against the current column.
-	if !yaml_parser_unroll_indent(parser, parser.mark.column, scan_mark) {
-		return false
-	}
-
-	// Ensure that the buffer contains at least 4 characters.  4 is the length
-	// of the longest indicators ('--- ' and '... ').
-	if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
-		return false
-	}
-
-	// Is it the end of the stream?
-	if is_z(parser.buffer, parser.buffer_pos) {
-		return yaml_parser_fetch_stream_end(parser)
-	}
-
-	// Is it a directive?
-	if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {
-		return yaml_parser_fetch_directive(parser)
-	}
-
-	buf := parser.buffer
-	pos := parser.buffer_pos
-
-	// Is it the document start indicator?
-	if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {
-		return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)
-	}
-
-	// Is it the document end indicator?
-	if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {
-		return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)
-	}
-
-	comment_mark := parser.mark
-	if len(parser.tokens) > 0 && (parser.flow_level == 0 && buf[pos] == ':' || parser.flow_level > 0 && buf[pos] == ',') {
-		// Associate any following comments with the prior token.
-		comment_mark = parser.tokens[len(parser.tokens)-1].start_mark
-	}
-	defer func() {
-		if !ok {
-			return
-		}
-		if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN {
-			// Sequence indicators alone have no line comments. It becomes
-			// a head comment for whatever follows.
-			return
-		}
-		if !yaml_parser_scan_line_comment(parser, comment_mark) {
-			ok = false
-			return
-		}
-	}()
-
-	// Is it the flow sequence start indicator?
-	if buf[pos] == '[' {
-		return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)
-	}
-
-	// Is it the flow mapping start indicator?
-	if parser.buffer[parser.buffer_pos] == '{' {
-		return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)
-	}
-
-	// Is it the flow sequence end indicator?
-	if parser.buffer[parser.buffer_pos] == ']' {
-		return yaml_parser_fetch_flow_collection_end(parser,
-			yaml_FLOW_SEQUENCE_END_TOKEN)
-	}
-
-	// Is it the flow mapping end indicator?
-	if parser.buffer[parser.buffer_pos] == '}' {
-		return yaml_parser_fetch_flow_collection_end(parser,
-			yaml_FLOW_MAPPING_END_TOKEN)
-	}
-
-	// Is it the flow entry indicator?
-	if parser.buffer[parser.buffer_pos] == ',' {
-		return yaml_parser_fetch_flow_entry(parser)
-	}
-
-	// Is it the block entry indicator?
-	if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {
-		return yaml_parser_fetch_block_entry(parser)
-	}
-
-	// Is it the key indicator?
-	if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
-		return yaml_parser_fetch_key(parser)
-	}
-
-	// Is it the value indicator?
-	if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
-		return yaml_parser_fetch_value(parser)
-	}
-
-	// Is it an alias?
-	if parser.buffer[parser.buffer_pos] == '*' {
-		return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)
-	}
-
-	// Is it an anchor?
-	if parser.buffer[parser.buffer_pos] == '&' {
-		return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)
-	}
-
-	// Is it a tag?
-	if parser.buffer[parser.buffer_pos] == '!' {
-		return yaml_parser_fetch_tag(parser)
-	}
-
-	// Is it a literal scalar?
-	if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {
-		return yaml_parser_fetch_block_scalar(parser, true)
-	}
-
-	// Is it a folded scalar?
-	if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {
-		return yaml_parser_fetch_block_scalar(parser, false)
-	}
-
-	// Is it a single-quoted scalar?
-	if parser.buffer[parser.buffer_pos] == '\'' {
-		return yaml_parser_fetch_flow_scalar(parser, true)
-	}
-
-	// Is it a double-quoted scalar?
-	if parser.buffer[parser.buffer_pos] == '"' {
-		return yaml_parser_fetch_flow_scalar(parser, false)
-	}
-
-	// Is it a plain scalar?
-	//
-	// A plain scalar may start with any non-blank characters except
-	//
-	//      '-', '?', ':', ',', '[', ']', '{', '}',
-	//      '#', '&', '*', '!', '|', '>', '\'', '\"',
-	//      '%', '@', '`'.
-	//
-	// In the block context (and, for the '-' indicator, in the flow context
-	// too), it may also start with the characters
-	//
-	//      '-', '?', ':'
-	//
-	// if it is followed by a non-space character.
-	//
-	// The last rule is more restrictive than the specification requires.
-	// [Go] TODO Make this logic more reasonable.
-	//switch parser.buffer[parser.buffer_pos] {
-	//case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`':
-	//}
-	if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||
-		parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||
-		parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||
-		parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
-		parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||
-		parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||
-		parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||
-		parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||
-		parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||
-		parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||
-		(parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||
-		(parser.flow_level == 0 &&
-			(parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&
-			!is_blankz(parser.buffer, parser.buffer_pos+1)) {
-		return yaml_parser_fetch_plain_scalar(parser)
-	}
-
-	// If we don't determine the token type so far, it is an error.
-	return yaml_parser_set_scanner_error(parser,
-		"while scanning for the next token", parser.mark,
-		"found character that cannot start any token")
-}
-
-func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
-	if !simple_key.possible {
-		return false, true
-	}
-
-	// The 1.2 specification says:
-	//
-	//     "If the ? indicator is omitted, parsing needs to see past the
-	//     implicit key to recognize it as such. To limit the amount of
-	//     lookahead required, the “:” indicator must appear at most 1024
-	//     Unicode characters beyond the start of the key. In addition, the key
-	//     is restricted to a single line."
-	//
-	if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
-		// Check if the potential simple key to be removed is required.
-		if simple_key.required {
-			return false, yaml_parser_set_scanner_error(parser,
-				"while scanning a simple key", simple_key.mark,
-				"could not find expected ':'")
-		}
-		simple_key.possible = false
-		return false, true
-	}
-	return true, true
-}
-
-// Check if a simple key may start at the current position and add it if
-// needed.
-func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
-	// A simple key is required at the current position if the scanner is in
-	// the block context and the current column coincides with the indentation
-	// level.
-
-	required := parser.flow_level == 0 && parser.indent == parser.mark.column
-
-	//
-	// If the current position may start a simple key, save it.
-	//
-	if parser.simple_key_allowed {
-		simple_key := yaml_simple_key_t{
-			possible:     true,
-			required:     required,
-			token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
-			mark:         parser.mark,
-		}
-
-		if !yaml_parser_remove_simple_key(parser) {
-			return false
-		}
-		parser.simple_keys[len(parser.simple_keys)-1] = simple_key
-		parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
-	}
-	return true
-}
-
-// Remove a potential simple key at the current flow level.
-func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
-	i := len(parser.simple_keys) - 1
-	if parser.simple_keys[i].possible {
-		// If the key is required, it is an error.
-		if parser.simple_keys[i].required {
-			return yaml_parser_set_scanner_error(parser,
-				"while scanning a simple key", parser.simple_keys[i].mark,
-				"could not find expected ':'")
-		}
-		// Remove the key from the stack.
-		parser.simple_keys[i].possible = false
-		delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
-	}
-	return true
-}
-
-// max_flow_level limits the flow_level
-const max_flow_level = 10000
-
-// Increase the flow level and resize the simple key list if needed.
-func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
-	// Reset the simple key on the next level.
-	parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
-		possible:     false,
-		required:     false,
-		token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
-		mark:         parser.mark,
-	})
-
-	// Increase the flow level.
-	parser.flow_level++
-	if parser.flow_level > max_flow_level {
-		return yaml_parser_set_scanner_error(parser,
-			"while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark,
-			fmt.Sprintf("exceeded max depth of %d", max_flow_level))
-	}
-	return true
-}
-
-// Decrease the flow level.
-func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
-	if parser.flow_level > 0 {
-		parser.flow_level--
-		last := len(parser.simple_keys) - 1
-		delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
-		parser.simple_keys = parser.simple_keys[:last]
-	}
-	return true
-}
-
-// max_indents limits the indents stack size
-const max_indents = 10000
-
-// Push the current indentation level to the stack and set the new level
-// the current column is greater than the indentation level.  In this case,
-// append or insert the specified token into the token queue.
-func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {
-	// In the flow context, do nothing.
-	if parser.flow_level > 0 {
-		return true
-	}
-
-	if parser.indent < column {
-		// Push the current indentation level to the stack and set the new
-		// indentation level.
-		parser.indents = append(parser.indents, parser.indent)
-		parser.indent = column
-		if len(parser.indents) > max_indents {
-			return yaml_parser_set_scanner_error(parser,
-				"while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark,
-				fmt.Sprintf("exceeded max depth of %d", max_indents))
-		}
-
-		// Create a token and insert it into the queue.
-		token := yaml_token_t{
-			typ:        typ,
-			start_mark: mark,
-			end_mark:   mark,
-		}
-		if number > -1 {
-			number -= parser.tokens_parsed
-		}
-		yaml_insert_token(parser, number, &token)
-	}
-	return true
-}
-
-// Pop indentation levels from the indents stack until the current level
-// becomes less or equal to the column.  For each indentation level, append
-// the BLOCK-END token.
-func yaml_parser_unroll_indent(parser *yaml_parser_t, column int, scan_mark yaml_mark_t) bool {
-	// In the flow context, do nothing.
-	if parser.flow_level > 0 {
-		return true
-	}
-
-	block_mark := scan_mark
-	block_mark.index--
-
-	// Loop through the indentation levels in the stack.
-	for parser.indent > column {
-
-		// [Go] Reposition the end token before potential following
-		//      foot comments of parent blocks. For that, search
-		//      backwards for recent comments that were at the same
-		//      indent as the block that is ending now.
-		stop_index := block_mark.index
-		for i := len(parser.comments) - 1; i >= 0; i-- {
-			comment := &parser.comments[i]
-
-			if comment.end_mark.index < stop_index {
-				// Don't go back beyond the start of the comment/whitespace scan, unless column < 0.
-				// If requested indent column is < 0, then the document is over and everything else
-				// is a foot anyway.
-				break
-			}
-			if comment.start_mark.column == parser.indent+1 {
-				// This is a good match. But maybe there's a former comment
-				// at that same indent level, so keep searching.
-				block_mark = comment.start_mark
-			}
-
-			// While the end of the former comment matches with
-			// the start of the following one, we know there's
-			// nothing in between and scanning is still safe.
-			stop_index = comment.scan_mark.index
-		}
-
-		// Create a token and append it to the queue.
-		token := yaml_token_t{
-			typ:        yaml_BLOCK_END_TOKEN,
-			start_mark: block_mark,
-			end_mark:   block_mark,
-		}
-		yaml_insert_token(parser, -1, &token)
-
-		// Pop the indentation level.
-		parser.indent = parser.indents[len(parser.indents)-1]
-		parser.indents = parser.indents[:len(parser.indents)-1]
-	}
-	return true
-}
-
-// Initialize the scanner and produce the STREAM-START token.
-func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
-
-	// Set the initial indentation.
-	parser.indent = -1
-
-	// Initialize the simple key stack.
-	parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
-
-	parser.simple_keys_by_tok = make(map[int]int)
-
-	// A simple key is allowed at the beginning of the stream.
-	parser.simple_key_allowed = true
-
-	// We have started.
-	parser.stream_start_produced = true
-
-	// Create the STREAM-START token and append it to the queue.
-	token := yaml_token_t{
-		typ:        yaml_STREAM_START_TOKEN,
-		start_mark: parser.mark,
-		end_mark:   parser.mark,
-		encoding:   parser.encoding,
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the STREAM-END token and shut down the scanner.
-func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {
-
-	// Force new line.
-	if parser.mark.column != 0 {
-		parser.mark.column = 0
-		parser.mark.line++
-	}
-
-	// Reset the indentation level.
-	if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
-		return false
-	}
-
-	// Reset simple keys.
-	if !yaml_parser_remove_simple_key(parser) {
-		return false
-	}
-
-	parser.simple_key_allowed = false
-
-	// Create the STREAM-END token and append it to the queue.
-	token := yaml_token_t{
-		typ:        yaml_STREAM_END_TOKEN,
-		start_mark: parser.mark,
-		end_mark:   parser.mark,
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
-func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {
-	// Reset the indentation level.
-	if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
-		return false
-	}
-
-	// Reset simple keys.
-	if !yaml_parser_remove_simple_key(parser) {
-		return false
-	}
-
-	parser.simple_key_allowed = false
-
-	// Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.
-	token := yaml_token_t{}
-	if !yaml_parser_scan_directive(parser, &token) {
-		return false
-	}
-	// Append the token to the queue.
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the DOCUMENT-START or DOCUMENT-END token.
-func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {
-	// Reset the indentation level.
-	if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
-		return false
-	}
-
-	// Reset simple keys.
-	if !yaml_parser_remove_simple_key(parser) {
-		return false
-	}
-
-	parser.simple_key_allowed = false
-
-	// Consume the token.
-	start_mark := parser.mark
-
-	skip(parser)
-	skip(parser)
-	skip(parser)
-
-	end_mark := parser.mark
-
-	// Create the DOCUMENT-START or DOCUMENT-END token.
-	token := yaml_token_t{
-		typ:        typ,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-	}
-	// Append the token to the queue.
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
-func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {
-
-	// The indicators '[' and '{' may start a simple key.
-	if !yaml_parser_save_simple_key(parser) {
-		return false
-	}
-
-	// Increase the flow level.
-	if !yaml_parser_increase_flow_level(parser) {
-		return false
-	}
-
-	// A simple key may follow the indicators '[' and '{'.
-	parser.simple_key_allowed = true
-
-	// Consume the token.
-	start_mark := parser.mark
-	skip(parser)
-	end_mark := parser.mark
-
-	// Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.
-	token := yaml_token_t{
-		typ:        typ,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-	}
-	// Append the token to the queue.
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
-func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {
-	// Reset any potential simple key on the current flow level.
-	if !yaml_parser_remove_simple_key(parser) {
-		return false
-	}
-
-	// Decrease the flow level.
-	if !yaml_parser_decrease_flow_level(parser) {
-		return false
-	}
-
-	// No simple keys after the indicators ']' and '}'.
-	parser.simple_key_allowed = false
-
-	// Consume the token.
-
-	start_mark := parser.mark
-	skip(parser)
-	end_mark := parser.mark
-
-	// Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.
-	token := yaml_token_t{
-		typ:        typ,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-	}
-	// Append the token to the queue.
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the FLOW-ENTRY token.
-func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {
-	// Reset any potential simple keys on the current flow level.
-	if !yaml_parser_remove_simple_key(parser) {
-		return false
-	}
-
-	// Simple keys are allowed after ','.
-	parser.simple_key_allowed = true
-
-	// Consume the token.
-	start_mark := parser.mark
-	skip(parser)
-	end_mark := parser.mark
-
-	// Create the FLOW-ENTRY token and append it to the queue.
-	token := yaml_token_t{
-		typ:        yaml_FLOW_ENTRY_TOKEN,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the BLOCK-ENTRY token.
-func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {
-	// Check if the scanner is in the block context.
-	if parser.flow_level == 0 {
-		// Check if we are allowed to start a new entry.
-		if !parser.simple_key_allowed {
-			return yaml_parser_set_scanner_error(parser, "", parser.mark,
-				"block sequence entries are not allowed in this context")
-		}
-		// Add the BLOCK-SEQUENCE-START token if needed.
-		if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {
-			return false
-		}
-	} else {
-		// It is an error for the '-' indicator to occur in the flow context,
-		// but we let the Parser detect and report about it because the Parser
-		// is able to point to the context.
-	}
-
-	// Reset any potential simple keys on the current flow level.
-	if !yaml_parser_remove_simple_key(parser) {
-		return false
-	}
-
-	// Simple keys are allowed after '-'.
-	parser.simple_key_allowed = true
-
-	// Consume the token.
-	start_mark := parser.mark
-	skip(parser)
-	end_mark := parser.mark
-
-	// Create the BLOCK-ENTRY token and append it to the queue.
-	token := yaml_token_t{
-		typ:        yaml_BLOCK_ENTRY_TOKEN,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the KEY token.
-func yaml_parser_fetch_key(parser *yaml_parser_t) bool {
-
-	// In the block context, additional checks are required.
-	if parser.flow_level == 0 {
-		// Check if we are allowed to start a new key (not nessesary simple).
-		if !parser.simple_key_allowed {
-			return yaml_parser_set_scanner_error(parser, "", parser.mark,
-				"mapping keys are not allowed in this context")
-		}
-		// Add the BLOCK-MAPPING-START token if needed.
-		if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
-			return false
-		}
-	}
-
-	// Reset any potential simple keys on the current flow level.
-	if !yaml_parser_remove_simple_key(parser) {
-		return false
-	}
-
-	// Simple keys are allowed after '?' in the block context.
-	parser.simple_key_allowed = parser.flow_level == 0
-
-	// Consume the token.
-	start_mark := parser.mark
-	skip(parser)
-	end_mark := parser.mark
-
-	// Create the KEY token and append it to the queue.
-	token := yaml_token_t{
-		typ:        yaml_KEY_TOKEN,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the VALUE token.
-func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
-
-	simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
-
-	// Have we found a simple key?
-	if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
-		return false
-
-	} else if valid {
-
-		// Create the KEY token and insert it into the queue.
-		token := yaml_token_t{
-			typ:        yaml_KEY_TOKEN,
-			start_mark: simple_key.mark,
-			end_mark:   simple_key.mark,
-		}
-		yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)
-
-		// In the block context, we may need to add the BLOCK-MAPPING-START token.
-		if !yaml_parser_roll_indent(parser, simple_key.mark.column,
-			simple_key.token_number,
-			yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {
-			return false
-		}
-
-		// Remove the simple key.
-		simple_key.possible = false
-		delete(parser.simple_keys_by_tok, simple_key.token_number)
-
-		// A simple key cannot follow another simple key.
-		parser.simple_key_allowed = false
-
-	} else {
-		// The ':' indicator follows a complex key.
-
-		// In the block context, extra checks are required.
-		if parser.flow_level == 0 {
-
-			// Check if we are allowed to start a complex value.
-			if !parser.simple_key_allowed {
-				return yaml_parser_set_scanner_error(parser, "", parser.mark,
-					"mapping values are not allowed in this context")
-			}
-
-			// Add the BLOCK-MAPPING-START token if needed.
-			if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
-				return false
-			}
-		}
-
-		// Simple keys after ':' are allowed in the block context.
-		parser.simple_key_allowed = parser.flow_level == 0
-	}
-
-	// Consume the token.
-	start_mark := parser.mark
-	skip(parser)
-	end_mark := parser.mark
-
-	// Create the VALUE token and append it to the queue.
-	token := yaml_token_t{
-		typ:        yaml_VALUE_TOKEN,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the ALIAS or ANCHOR token.
-func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {
-	// An anchor or an alias could be a simple key.
-	if !yaml_parser_save_simple_key(parser) {
-		return false
-	}
-
-	// A simple key cannot follow an anchor or an alias.
-	parser.simple_key_allowed = false
-
-	// Create the ALIAS or ANCHOR token and append it to the queue.
-	var token yaml_token_t
-	if !yaml_parser_scan_anchor(parser, &token, typ) {
-		return false
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the TAG token.
-func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {
-	// A tag could be a simple key.
-	if !yaml_parser_save_simple_key(parser) {
-		return false
-	}
-
-	// A simple key cannot follow a tag.
-	parser.simple_key_allowed = false
-
-	// Create the TAG token and append it to the queue.
-	var token yaml_token_t
-	if !yaml_parser_scan_tag(parser, &token) {
-		return false
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
-func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {
-	// Remove any potential simple keys.
-	if !yaml_parser_remove_simple_key(parser) {
-		return false
-	}
-
-	// A simple key may follow a block scalar.
-	parser.simple_key_allowed = true
-
-	// Create the SCALAR token and append it to the queue.
-	var token yaml_token_t
-	if !yaml_parser_scan_block_scalar(parser, &token, literal) {
-		return false
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
-func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {
-	// A plain scalar could be a simple key.
-	if !yaml_parser_save_simple_key(parser) {
-		return false
-	}
-
-	// A simple key cannot follow a flow scalar.
-	parser.simple_key_allowed = false
-
-	// Create the SCALAR token and append it to the queue.
-	var token yaml_token_t
-	if !yaml_parser_scan_flow_scalar(parser, &token, single) {
-		return false
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Produce the SCALAR(...,plain) token.
-func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {
-	// A plain scalar could be a simple key.
-	if !yaml_parser_save_simple_key(parser) {
-		return false
-	}
-
-	// A simple key cannot follow a flow scalar.
-	parser.simple_key_allowed = false
-
-	// Create the SCALAR token and append it to the queue.
-	var token yaml_token_t
-	if !yaml_parser_scan_plain_scalar(parser, &token) {
-		return false
-	}
-	yaml_insert_token(parser, -1, &token)
-	return true
-}
-
-// Eat whitespaces and comments until the next token is found.
-func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
-
-	scan_mark := parser.mark
-
-	// Until the next token is not found.
-	for {
-		// Allow the BOM mark to start a line.
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-		if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {
-			skip(parser)
-		}
-
-		// Eat whitespaces.
-		// Tabs are allowed:
-		//  - in the flow context
-		//  - in the block context, but not at the beginning of the line or
-		//  after '-', '?', or ':' (complex value).
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-
-		for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {
-			skip(parser)
-			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-				return false
-			}
-		}
-
-		// Check if we just had a line comment under a sequence entry that
-		// looks more like a header to the following content. Similar to this:
-		//
-		// - # The comment
-		//   - Some data
-		//
-		// If so, transform the line comment to a head comment and reposition.
-		if len(parser.comments) > 0 && len(parser.tokens) > 1 {
-			tokenA := parser.tokens[len(parser.tokens)-2]
-			tokenB := parser.tokens[len(parser.tokens)-1]
-			comment := &parser.comments[len(parser.comments)-1]
-			if tokenA.typ == yaml_BLOCK_SEQUENCE_START_TOKEN && tokenB.typ == yaml_BLOCK_ENTRY_TOKEN && len(comment.line) > 0 && !is_break(parser.buffer, parser.buffer_pos) {
-				// If it was in the prior line, reposition so it becomes a
-				// header of the follow up token. Otherwise, keep it in place
-				// so it becomes a header of the former.
-				comment.head = comment.line
-				comment.line = nil
-				if comment.start_mark.line == parser.mark.line-1 {
-					comment.token_mark = parser.mark
-				}
-			}
-		}
-
-		// Eat a comment until a line break.
-		if parser.buffer[parser.buffer_pos] == '#' {
-			if !yaml_parser_scan_comments(parser, scan_mark) {
-				return false
-			}
-		}
-
-		// If it is a line break, eat it.
-		if is_break(parser.buffer, parser.buffer_pos) {
-			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-				return false
-			}
-			skip_line(parser)
-
-			// In the block context, a new line may start a simple key.
-			if parser.flow_level == 0 {
-				parser.simple_key_allowed = true
-			}
-		} else {
-			break // We have found a token.
-		}
-	}
-
-	return true
-}
-
-// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
-//
-// Scope:
-//
-//	%YAML    1.1    # a comment \n
-//	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//	%TAG    !yaml!  tag:yaml.org,2002:  \n
-//	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
-	// Eat '%'.
-	start_mark := parser.mark
-	skip(parser)
-
-	// Scan the directive name.
-	var name []byte
-	if !yaml_parser_scan_directive_name(parser, start_mark, &name) {
-		return false
-	}
-
-	// Is it a YAML directive?
-	if bytes.Equal(name, []byte("YAML")) {
-		// Scan the VERSION directive value.
-		var major, minor int8
-		if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {
-			return false
-		}
-		end_mark := parser.mark
-
-		// Create a VERSION-DIRECTIVE token.
-		*token = yaml_token_t{
-			typ:        yaml_VERSION_DIRECTIVE_TOKEN,
-			start_mark: start_mark,
-			end_mark:   end_mark,
-			major:      major,
-			minor:      minor,
-		}
-
-		// Is it a TAG directive?
-	} else if bytes.Equal(name, []byte("TAG")) {
-		// Scan the TAG directive value.
-		var handle, prefix []byte
-		if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {
-			return false
-		}
-		end_mark := parser.mark
-
-		// Create a TAG-DIRECTIVE token.
-		*token = yaml_token_t{
-			typ:        yaml_TAG_DIRECTIVE_TOKEN,
-			start_mark: start_mark,
-			end_mark:   end_mark,
-			value:      handle,
-			prefix:     prefix,
-		}
-
-		// Unknown directive.
-	} else {
-		yaml_parser_set_scanner_error(parser, "while scanning a directive",
-			start_mark, "found unknown directive name")
-		return false
-	}
-
-	// Eat the rest of the line including any comments.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-
-	for is_blank(parser.buffer, parser.buffer_pos) {
-		skip(parser)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-
-	if parser.buffer[parser.buffer_pos] == '#' {
-		// [Go] Discard this inline comment for the time being.
-		//if !yaml_parser_scan_line_comment(parser, start_mark) {
-		//	return false
-		//}
-		for !is_breakz(parser.buffer, parser.buffer_pos) {
-			skip(parser)
-			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-				return false
-			}
-		}
-	}
-
-	// Check if we are at the end of the line.
-	if !is_breakz(parser.buffer, parser.buffer_pos) {
-		yaml_parser_set_scanner_error(parser, "while scanning a directive",
-			start_mark, "did not find expected comment or line break")
-		return false
-	}
-
-	// Eat a line break.
-	if is_break(parser.buffer, parser.buffer_pos) {
-		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-			return false
-		}
-		skip_line(parser)
-	}
-
-	return true
-}
-
-// Scan the directive name.
-//
-// Scope:
-//
-//	%YAML   1.1     # a comment \n
-//	 ^^^^
-//	%TAG    !yaml!  tag:yaml.org,2002:  \n
-//	 ^^^
-func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
-	// Consume the directive name.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-
-	var s []byte
-	for is_alpha(parser.buffer, parser.buffer_pos) {
-		s = read(parser, s)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-
-	// Check if the name is empty.
-	if len(s) == 0 {
-		yaml_parser_set_scanner_error(parser, "while scanning a directive",
-			start_mark, "could not find expected directive name")
-		return false
-	}
-
-	// Check for an blank character after the name.
-	if !is_blankz(parser.buffer, parser.buffer_pos) {
-		yaml_parser_set_scanner_error(parser, "while scanning a directive",
-			start_mark, "found unexpected non-alphabetical character")
-		return false
-	}
-	*name = s
-	return true
-}
-
-// Scan the value of VERSION-DIRECTIVE.
-//
-// Scope:
-//
-//	%YAML   1.1     # a comment \n
-//	     ^^^^^^
-func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {
-	// Eat whitespaces.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	for is_blank(parser.buffer, parser.buffer_pos) {
-		skip(parser)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-
-	// Consume the major version number.
-	if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {
-		return false
-	}
-
-	// Eat '.'.
-	if parser.buffer[parser.buffer_pos] != '.' {
-		return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
-			start_mark, "did not find expected digit or '.' character")
-	}
-
-	skip(parser)
-
-	// Consume the minor version number.
-	if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {
-		return false
-	}
-	return true
-}
-
-const max_number_length = 2
-
-// Scan the version number of VERSION-DIRECTIVE.
-//
-// Scope:
-//
-//	%YAML   1.1     # a comment \n
-//	        ^
-//	%YAML   1.1     # a comment \n
-//	          ^
-func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {
-
-	// Repeat while the next character is digit.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	var value, length int8
-	for is_digit(parser.buffer, parser.buffer_pos) {
-		// Check if the number is too long.
-		length++
-		if length > max_number_length {
-			return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
-				start_mark, "found extremely long version number")
-		}
-		value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos))
-		skip(parser)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-
-	// Check if the number was present.
-	if length == 0 {
-		return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
-			start_mark, "did not find expected version number")
-	}
-	*number = value
-	return true
-}
-
-// Scan the value of a TAG-DIRECTIVE token.
-//
-// Scope:
-//
-//	%TAG    !yaml!  tag:yaml.org,2002:  \n
-//	    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
-	var handle_value, prefix_value []byte
-
-	// Eat whitespaces.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-
-	for is_blank(parser.buffer, parser.buffer_pos) {
-		skip(parser)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-
-	// Scan a handle.
-	if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {
-		return false
-	}
-
-	// Expect a whitespace.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	if !is_blank(parser.buffer, parser.buffer_pos) {
-		yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
-			start_mark, "did not find expected whitespace")
-		return false
-	}
-
-	// Eat whitespaces.
-	for is_blank(parser.buffer, parser.buffer_pos) {
-		skip(parser)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-
-	// Scan a prefix.
-	if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {
-		return false
-	}
-
-	// Expect a whitespace or line break.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	if !is_blankz(parser.buffer, parser.buffer_pos) {
-		yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
-			start_mark, "did not find expected whitespace or line break")
-		return false
-	}
-
-	*handle = handle_value
-	*prefix = prefix_value
-	return true
-}
-
-func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {
-	var s []byte
-
-	// Eat the indicator character.
-	start_mark := parser.mark
-	skip(parser)
-
-	// Consume the value.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-
-	for is_alpha(parser.buffer, parser.buffer_pos) {
-		s = read(parser, s)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-
-	end_mark := parser.mark
-
-	/*
-	 * Check if length of the anchor is greater than 0 and it is followed by
-	 * a whitespace character or one of the indicators:
-	 *
-	 *      '?', ':', ',', ']', '}', '%', '@', '`'.
-	 */
-
-	if len(s) == 0 ||
-		!(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||
-			parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||
-			parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||
-			parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||
-			parser.buffer[parser.buffer_pos] == '`') {
-		context := "while scanning an alias"
-		if typ == yaml_ANCHOR_TOKEN {
-			context = "while scanning an anchor"
-		}
-		yaml_parser_set_scanner_error(parser, context, start_mark,
-			"did not find expected alphabetic or numeric character")
-		return false
-	}
-
-	// Create a token.
-	*token = yaml_token_t{
-		typ:        typ,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-		value:      s,
-	}
-
-	return true
-}
-
-/*
- * Scan a TAG token.
- */
-
-func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {
-	var handle, suffix []byte
-
-	start_mark := parser.mark
-
-	// Check if the tag is in the canonical form.
-	if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-		return false
-	}
-
-	if parser.buffer[parser.buffer_pos+1] == '<' {
-		// Keep the handle as ''
-
-		// Eat '!<'
-		skip(parser)
-		skip(parser)
-
-		// Consume the tag value.
-		if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
-			return false
-		}
-
-		// Check for '>' and eat it.
-		if parser.buffer[parser.buffer_pos] != '>' {
-			yaml_parser_set_scanner_error(parser, "while scanning a tag",
-				start_mark, "did not find the expected '>'")
-			return false
-		}
-
-		skip(parser)
-	} else {
-		// The tag has either the '!suffix' or the '!handle!suffix' form.
-
-		// First, try to scan a handle.
-		if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {
-			return false
-		}
-
-		// Check if it is, indeed, handle.
-		if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {
-			// Scan the suffix now.
-			if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
-				return false
-			}
-		} else {
-			// It wasn't a handle after all.  Scan the rest of the tag.
-			if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {
-				return false
-			}
-
-			// Set the handle to '!'.
-			handle = []byte{'!'}
-
-			// A special case: the '!' tag.  Set the handle to '' and the
-			// suffix to '!'.
-			if len(suffix) == 0 {
-				handle, suffix = suffix, handle
-			}
-		}
-	}
-
-	// Check the character which ends the tag.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	if !is_blankz(parser.buffer, parser.buffer_pos) {
-		yaml_parser_set_scanner_error(parser, "while scanning a tag",
-			start_mark, "did not find expected whitespace or line break")
-		return false
-	}
-
-	end_mark := parser.mark
-
-	// Create a token.
-	*token = yaml_token_t{
-		typ:        yaml_TAG_TOKEN,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-		value:      handle,
-		suffix:     suffix,
-	}
-	return true
-}
-
-// Scan a tag handle.
-func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {
-	// Check the initial '!' character.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	if parser.buffer[parser.buffer_pos] != '!' {
-		yaml_parser_set_scanner_tag_error(parser, directive,
-			start_mark, "did not find expected '!'")
-		return false
-	}
-
-	var s []byte
-
-	// Copy the '!' character.
-	s = read(parser, s)
-
-	// Copy all subsequent alphabetical and numerical characters.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	for is_alpha(parser.buffer, parser.buffer_pos) {
-		s = read(parser, s)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-
-	// Check if the trailing character is '!' and copy it.
-	if parser.buffer[parser.buffer_pos] == '!' {
-		s = read(parser, s)
-	} else {
-		// It's either the '!' tag or not really a tag handle.  If it's a %TAG
-		// directive, it's an error.  If it's a tag token, it must be a part of URI.
-		if directive && string(s) != "!" {
-			yaml_parser_set_scanner_tag_error(parser, directive,
-				start_mark, "did not find expected '!'")
-			return false
-		}
-	}
-
-	*handle = s
-	return true
-}
-
-// Scan a tag.
-func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
-	//size_t length = head ? strlen((char *)head) : 0
-	var s []byte
-	hasTag := len(head) > 0
-
-	// Copy the head if needed.
-	//
-	// Note that we don't copy the leading '!' character.
-	if len(head) > 1 {
-		s = append(s, head[1:]...)
-	}
-
-	// Scan the tag.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-
-	// The set of characters that may appear in URI is as follows:
-	//
-	//      '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
-	//      '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
-	//      '%'.
-	// [Go] TODO Convert this into more reasonable logic.
-	for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||
-		parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||
-		parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||
-		parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||
-		parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||
-		parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||
-		parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||
-		parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||
-		parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||
-		parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||
-		parser.buffer[parser.buffer_pos] == '%' {
-		// Check if it is a URI-escape sequence.
-		if parser.buffer[parser.buffer_pos] == '%' {
-			if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {
-				return false
-			}
-		} else {
-			s = read(parser, s)
-		}
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-		hasTag = true
-	}
-
-	if !hasTag {
-		yaml_parser_set_scanner_tag_error(parser, directive,
-			start_mark, "did not find expected tag URI")
-		return false
-	}
-	*uri = s
-	return true
-}
-
-// Decode an URI-escape sequence corresponding to a single UTF-8 character.
-func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {
-
-	// Decode the required number of characters.
-	w := 1024
-	for w > 0 {
-		// Check for a URI-escaped octet.
-		if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
-			return false
-		}
-
-		if !(parser.buffer[parser.buffer_pos] == '%' &&
-			is_hex(parser.buffer, parser.buffer_pos+1) &&
-			is_hex(parser.buffer, parser.buffer_pos+2)) {
-			return yaml_parser_set_scanner_tag_error(parser, directive,
-				start_mark, "did not find URI escaped octet")
-		}
-
-		// Get the octet.
-		octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))
-
-		// If it is the leading octet, determine the length of the UTF-8 sequence.
-		if w == 1024 {
-			w = width(octet)
-			if w == 0 {
-				return yaml_parser_set_scanner_tag_error(parser, directive,
-					start_mark, "found an incorrect leading UTF-8 octet")
-			}
-		} else {
-			// Check if the trailing octet is correct.
-			if octet&0xC0 != 0x80 {
-				return yaml_parser_set_scanner_tag_error(parser, directive,
-					start_mark, "found an incorrect trailing UTF-8 octet")
-			}
-		}
-
-		// Copy the octet and move the pointers.
-		*s = append(*s, octet)
-		skip(parser)
-		skip(parser)
-		skip(parser)
-		w--
-	}
-	return true
-}
-
-// Scan a block scalar.
-func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {
-	// Eat the indicator '|' or '>'.
-	start_mark := parser.mark
-	skip(parser)
-
-	// Scan the additional block scalar indicators.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-
-	// Check for a chomping indicator.
-	var chomping, increment int
-	if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
-		// Set the chomping method and eat the indicator.
-		if parser.buffer[parser.buffer_pos] == '+' {
-			chomping = +1
-		} else {
-			chomping = -1
-		}
-		skip(parser)
-
-		// Check for an indentation indicator.
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-		if is_digit(parser.buffer, parser.buffer_pos) {
-			// Check that the indentation is greater than 0.
-			if parser.buffer[parser.buffer_pos] == '0' {
-				yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
-					start_mark, "found an indentation indicator equal to 0")
-				return false
-			}
-
-			// Get the indentation level and eat the indicator.
-			increment = as_digit(parser.buffer, parser.buffer_pos)
-			skip(parser)
-		}
-
-	} else if is_digit(parser.buffer, parser.buffer_pos) {
-		// Do the same as above, but in the opposite order.
-
-		if parser.buffer[parser.buffer_pos] == '0' {
-			yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
-				start_mark, "found an indentation indicator equal to 0")
-			return false
-		}
-		increment = as_digit(parser.buffer, parser.buffer_pos)
-		skip(parser)
-
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-		if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
-			if parser.buffer[parser.buffer_pos] == '+' {
-				chomping = +1
-			} else {
-				chomping = -1
-			}
-			skip(parser)
-		}
-	}
-
-	// Eat whitespaces and comments to the end of the line.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	for is_blank(parser.buffer, parser.buffer_pos) {
-		skip(parser)
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-	}
-	if parser.buffer[parser.buffer_pos] == '#' {
-		if !yaml_parser_scan_line_comment(parser, start_mark) {
-			return false
-		}
-		for !is_breakz(parser.buffer, parser.buffer_pos) {
-			skip(parser)
-			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-				return false
-			}
-		}
-	}
-
-	// Check if we are at the end of the line.
-	if !is_breakz(parser.buffer, parser.buffer_pos) {
-		yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
-			start_mark, "did not find expected comment or line break")
-		return false
-	}
-
-	// Eat a line break.
-	if is_break(parser.buffer, parser.buffer_pos) {
-		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-			return false
-		}
-		skip_line(parser)
-	}
-
-	end_mark := parser.mark
-
-	// Set the indentation level if it was specified.
-	var indent int
-	if increment > 0 {
-		if parser.indent >= 0 {
-			indent = parser.indent + increment
-		} else {
-			indent = increment
-		}
-	}
-
-	// Scan the leading line breaks and determine the indentation level if needed.
-	var s, leading_break, trailing_breaks []byte
-	if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
-		return false
-	}
-
-	// Scan the block scalar content.
-	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-		return false
-	}
-	var leading_blank, trailing_blank bool
-	for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {
-		// We are at the beginning of a non-empty line.
-
-		// Is it a trailing whitespace?
-		trailing_blank = is_blank(parser.buffer, parser.buffer_pos)
-
-		// Check if we need to fold the leading line break.
-		if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' {
-			// Do we need to join the lines by space?
-			if len(trailing_breaks) == 0 {
-				s = append(s, ' ')
-			}
-		} else {
-			s = append(s, leading_break...)
-		}
-		leading_break = leading_break[:0]
-
-		// Append the remaining line breaks.
-		s = append(s, trailing_breaks...)
-		trailing_breaks = trailing_breaks[:0]
-
-		// Is it a leading whitespace?
-		leading_blank = is_blank(parser.buffer, parser.buffer_pos)
-
-		// Consume the current line.
-		for !is_breakz(parser.buffer, parser.buffer_pos) {
-			s = read(parser, s)
-			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-				return false
-			}
-		}
-
-		// Consume the line break.
-		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-			return false
-		}
-
-		leading_break = read_line(parser, leading_break)
-
-		// Eat the following indentation spaces and line breaks.
-		if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
-			return false
-		}
-	}
-
-	// Chomp the tail.
-	if chomping != -1 {
-		s = append(s, leading_break...)
-	}
-	if chomping == 1 {
-		s = append(s, trailing_breaks...)
-	}
-
-	// Create a token.
-	*token = yaml_token_t{
-		typ:        yaml_SCALAR_TOKEN,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-		value:      s,
-		style:      yaml_LITERAL_SCALAR_STYLE,
-	}
-	if !literal {
-		token.style = yaml_FOLDED_SCALAR_STYLE
-	}
-	return true
-}
-
-// Scan indentation spaces and line breaks for a block scalar.  Determine the
-// indentation level if needed.
-func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool {
-	*end_mark = parser.mark
-
-	// Eat the indentation spaces and line breaks.
-	max_indent := 0
-	for {
-		// Eat the indentation spaces.
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-		for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) {
-			skip(parser)
-			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-				return false
-			}
-		}
-		if parser.mark.column > max_indent {
-			max_indent = parser.mark.column
-		}
-
-		// Check for a tab character messing the indentation.
-		if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {
-			return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
-				start_mark, "found a tab character where an indentation space is expected")
-		}
-
-		// Have we found a non-empty line?
-		if !is_break(parser.buffer, parser.buffer_pos) {
-			break
-		}
-
-		// Consume the line break.
-		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-			return false
-		}
-		// [Go] Should really be returning breaks instead.
-		*breaks = read_line(parser, *breaks)
-		*end_mark = parser.mark
-	}
-
-	// Determine the indentation level if needed.
-	if *indent == 0 {
-		*indent = max_indent
-		if *indent < parser.indent+1 {
-			*indent = parser.indent + 1
-		}
-		if *indent < 1 {
-			*indent = 1
-		}
-	}
-	return true
-}
-
-// Scan a quoted scalar.
-func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {
-	// Eat the left quote.
-	start_mark := parser.mark
-	skip(parser)
-
-	// Consume the content of the quoted scalar.
-	var s, leading_break, trailing_breaks, whitespaces []byte
-	for {
-		// Check that there are no document indicators at the beginning of the line.
-		if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
-			return false
-		}
-
-		if parser.mark.column == 0 &&
-			((parser.buffer[parser.buffer_pos+0] == '-' &&
-				parser.buffer[parser.buffer_pos+1] == '-' &&
-				parser.buffer[parser.buffer_pos+2] == '-') ||
-				(parser.buffer[parser.buffer_pos+0] == '.' &&
-					parser.buffer[parser.buffer_pos+1] == '.' &&
-					parser.buffer[parser.buffer_pos+2] == '.')) &&
-			is_blankz(parser.buffer, parser.buffer_pos+3) {
-			yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
-				start_mark, "found unexpected document indicator")
-			return false
-		}
-
-		// Check for EOF.
-		if is_z(parser.buffer, parser.buffer_pos) {
-			yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
-				start_mark, "found unexpected end of stream")
-			return false
-		}
-
-		// Consume non-blank characters.
-		leading_blanks := false
-		for !is_blankz(parser.buffer, parser.buffer_pos) {
-			if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {
-				// Is is an escaped single quote.
-				s = append(s, '\'')
-				skip(parser)
-				skip(parser)
-
-			} else if single && parser.buffer[parser.buffer_pos] == '\'' {
-				// It is a right single quote.
-				break
-			} else if !single && parser.buffer[parser.buffer_pos] == '"' {
-				// It is a right double quote.
-				break
-
-			} else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {
-				// It is an escaped line break.
-				if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
-					return false
-				}
-				skip(parser)
-				skip_line(parser)
-				leading_blanks = true
-				break
-
-			} else if !single && parser.buffer[parser.buffer_pos] == '\\' {
-				// It is an escape sequence.
-				code_length := 0
-
-				// Check the escape character.
-				switch parser.buffer[parser.buffer_pos+1] {
-				case '0':
-					s = append(s, 0)
-				case 'a':
-					s = append(s, '\x07')
-				case 'b':
-					s = append(s, '\x08')
-				case 't', '\t':
-					s = append(s, '\x09')
-				case 'n':
-					s = append(s, '\x0A')
-				case 'v':
-					s = append(s, '\x0B')
-				case 'f':
-					s = append(s, '\x0C')
-				case 'r':
-					s = append(s, '\x0D')
-				case 'e':
-					s = append(s, '\x1B')
-				case ' ':
-					s = append(s, '\x20')
-				case '"':
-					s = append(s, '"')
-				case '\'':
-					s = append(s, '\'')
-				case '\\':
-					s = append(s, '\\')
-				case 'N': // NEL (#x85)
-					s = append(s, '\xC2')
-					s = append(s, '\x85')
-				case '_': // #xA0
-					s = append(s, '\xC2')
-					s = append(s, '\xA0')
-				case 'L': // LS (#x2028)
-					s = append(s, '\xE2')
-					s = append(s, '\x80')
-					s = append(s, '\xA8')
-				case 'P': // PS (#x2029)
-					s = append(s, '\xE2')
-					s = append(s, '\x80')
-					s = append(s, '\xA9')
-				case 'x':
-					code_length = 2
-				case 'u':
-					code_length = 4
-				case 'U':
-					code_length = 8
-				default:
-					yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
-						start_mark, "found unknown escape character")
-					return false
-				}
-
-				skip(parser)
-				skip(parser)
-
-				// Consume an arbitrary escape code.
-				if code_length > 0 {
-					var value int
-
-					// Scan the character value.
-					if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) {
-						return false
-					}
-					for k := 0; k < code_length; k++ {
-						if !is_hex(parser.buffer, parser.buffer_pos+k) {
-							yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
-								start_mark, "did not find expected hexdecimal number")
-							return false
-						}
-						value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)
-					}
-
-					// Check the value and write the character.
-					if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
-						yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
-							start_mark, "found invalid Unicode character escape code")
-						return false
-					}
-					if value <= 0x7F {
-						s = append(s, byte(value))
-					} else if value <= 0x7FF {
-						s = append(s, byte(0xC0+(value>>6)))
-						s = append(s, byte(0x80+(value&0x3F)))
-					} else if value <= 0xFFFF {
-						s = append(s, byte(0xE0+(value>>12)))
-						s = append(s, byte(0x80+((value>>6)&0x3F)))
-						s = append(s, byte(0x80+(value&0x3F)))
-					} else {
-						s = append(s, byte(0xF0+(value>>18)))
-						s = append(s, byte(0x80+((value>>12)&0x3F)))
-						s = append(s, byte(0x80+((value>>6)&0x3F)))
-						s = append(s, byte(0x80+(value&0x3F)))
-					}
-
-					// Advance the pointer.
-					for k := 0; k < code_length; k++ {
-						skip(parser)
-					}
-				}
-			} else {
-				// It is a non-escaped non-blank character.
-				s = read(parser, s)
-			}
-			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-				return false
-			}
-		}
-
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-
-		// Check if we are at the end of the scalar.
-		if single {
-			if parser.buffer[parser.buffer_pos] == '\'' {
-				break
-			}
-		} else {
-			if parser.buffer[parser.buffer_pos] == '"' {
-				break
-			}
-		}
-
-		// Consume blank characters.
-		for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
-			if is_blank(parser.buffer, parser.buffer_pos) {
-				// Consume a space or a tab character.
-				if !leading_blanks {
-					whitespaces = read(parser, whitespaces)
-				} else {
-					skip(parser)
-				}
-			} else {
-				if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-					return false
-				}
-
-				// Check if it is a first line break.
-				if !leading_blanks {
-					whitespaces = whitespaces[:0]
-					leading_break = read_line(parser, leading_break)
-					leading_blanks = true
-				} else {
-					trailing_breaks = read_line(parser, trailing_breaks)
-				}
-			}
-			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-				return false
-			}
-		}
-
-		// Join the whitespaces or fold line breaks.
-		if leading_blanks {
-			// Do we need to fold line breaks?
-			if len(leading_break) > 0 && leading_break[0] == '\n' {
-				if len(trailing_breaks) == 0 {
-					s = append(s, ' ')
-				} else {
-					s = append(s, trailing_breaks...)
-				}
-			} else {
-				s = append(s, leading_break...)
-				s = append(s, trailing_breaks...)
-			}
-			trailing_breaks = trailing_breaks[:0]
-			leading_break = leading_break[:0]
-		} else {
-			s = append(s, whitespaces...)
-			whitespaces = whitespaces[:0]
-		}
-	}
-
-	// Eat the right quote.
-	skip(parser)
-	end_mark := parser.mark
-
-	// Create a token.
-	*token = yaml_token_t{
-		typ:        yaml_SCALAR_TOKEN,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-		value:      s,
-		style:      yaml_SINGLE_QUOTED_SCALAR_STYLE,
-	}
-	if !single {
-		token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
-	}
-	return true
-}
-
-// Scan a plain scalar.
-func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {
-
-	var s, leading_break, trailing_breaks, whitespaces []byte
-	var leading_blanks bool
-	var indent = parser.indent + 1
-
-	start_mark := parser.mark
-	end_mark := parser.mark
-
-	// Consume the content of the plain scalar.
-	for {
-		// Check for a document indicator.
-		if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
-			return false
-		}
-		if parser.mark.column == 0 &&
-			((parser.buffer[parser.buffer_pos+0] == '-' &&
-				parser.buffer[parser.buffer_pos+1] == '-' &&
-				parser.buffer[parser.buffer_pos+2] == '-') ||
-				(parser.buffer[parser.buffer_pos+0] == '.' &&
-					parser.buffer[parser.buffer_pos+1] == '.' &&
-					parser.buffer[parser.buffer_pos+2] == '.')) &&
-			is_blankz(parser.buffer, parser.buffer_pos+3) {
-			break
-		}
-
-		// Check for a comment.
-		if parser.buffer[parser.buffer_pos] == '#' {
-			break
-		}
-
-		// Consume non-blank characters.
-		for !is_blankz(parser.buffer, parser.buffer_pos) {
-
-			// Check for indicators that may end a plain scalar.
-			if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
-				(parser.flow_level > 0 &&
-					(parser.buffer[parser.buffer_pos] == ',' ||
-						parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||
-						parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
-						parser.buffer[parser.buffer_pos] == '}')) {
-				break
-			}
-
-			// Check if we need to join whitespaces and breaks.
-			if leading_blanks || len(whitespaces) > 0 {
-				if leading_blanks {
-					// Do we need to fold line breaks?
-					if leading_break[0] == '\n' {
-						if len(trailing_breaks) == 0 {
-							s = append(s, ' ')
-						} else {
-							s = append(s, trailing_breaks...)
-						}
-					} else {
-						s = append(s, leading_break...)
-						s = append(s, trailing_breaks...)
-					}
-					trailing_breaks = trailing_breaks[:0]
-					leading_break = leading_break[:0]
-					leading_blanks = false
-				} else {
-					s = append(s, whitespaces...)
-					whitespaces = whitespaces[:0]
-				}
-			}
-
-			// Copy the character.
-			s = read(parser, s)
-
-			end_mark = parser.mark
-			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-				return false
-			}
-		}
-
-		// Is it the end?
-		if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {
-			break
-		}
-
-		// Consume blank characters.
-		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-			return false
-		}
-
-		for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
-			if is_blank(parser.buffer, parser.buffer_pos) {
-
-				// Check for tab characters that abuse indentation.
-				if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
-					yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
-						start_mark, "found a tab character that violates indentation")
-					return false
-				}
-
-				// Consume a space or a tab character.
-				if !leading_blanks {
-					whitespaces = read(parser, whitespaces)
-				} else {
-					skip(parser)
-				}
-			} else {
-				if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-					return false
-				}
-
-				// Check if it is a first line break.
-				if !leading_blanks {
-					whitespaces = whitespaces[:0]
-					leading_break = read_line(parser, leading_break)
-					leading_blanks = true
-				} else {
-					trailing_breaks = read_line(parser, trailing_breaks)
-				}
-			}
-			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-				return false
-			}
-		}
-
-		// Check indentation level.
-		if parser.flow_level == 0 && parser.mark.column < indent {
-			break
-		}
-	}
-
-	// Create a token.
-	*token = yaml_token_t{
-		typ:        yaml_SCALAR_TOKEN,
-		start_mark: start_mark,
-		end_mark:   end_mark,
-		value:      s,
-		style:      yaml_PLAIN_SCALAR_STYLE,
-	}
-
-	// Note that we change the 'simple_key_allowed' flag.
-	if leading_blanks {
-		parser.simple_key_allowed = true
-	}
-	return true
-}
-
-func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t) bool {
-	if parser.newlines > 0 {
-		return true
-	}
-
-	var start_mark yaml_mark_t
-	var text []byte
-
-	for peek := 0; peek < 512; peek++ {
-		if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
-			break
-		}
-		if is_blank(parser.buffer, parser.buffer_pos+peek) {
-			continue
-		}
-		if parser.buffer[parser.buffer_pos+peek] == '#' {
-			seen := parser.mark.index + peek
-			for {
-				if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-					return false
-				}
-				if is_breakz(parser.buffer, parser.buffer_pos) {
-					if parser.mark.index >= seen {
-						break
-					}
-					if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-						return false
-					}
-					skip_line(parser)
-				} else if parser.mark.index >= seen {
-					if len(text) == 0 {
-						start_mark = parser.mark
-					}
-					text = read(parser, text)
-				} else {
-					skip(parser)
-				}
-			}
-		}
-		break
-	}
-	if len(text) > 0 {
-		parser.comments = append(parser.comments, yaml_comment_t{
-			token_mark: token_mark,
-			start_mark: start_mark,
-			line:       text,
-		})
-	}
-	return true
-}
-
-func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) bool {
-	token := parser.tokens[len(parser.tokens)-1]
-
-	if token.typ == yaml_FLOW_ENTRY_TOKEN && len(parser.tokens) > 1 {
-		token = parser.tokens[len(parser.tokens)-2]
-	}
-
-	var token_mark = token.start_mark
-	var start_mark yaml_mark_t
-	var next_indent = parser.indent
-	if next_indent < 0 {
-		next_indent = 0
-	}
-
-	var recent_empty = false
-	var first_empty = parser.newlines <= 1
-
-	var line = parser.mark.line
-	var column = parser.mark.column
-
-	var text []byte
-
-	// The foot line is the place where a comment must start to
-	// still be considered as a foot of the prior content.
-	// If there's some content in the currently parsed line, then
-	// the foot is the line below it.
-	var foot_line = -1
-	if scan_mark.line > 0 {
-		foot_line = parser.mark.line - parser.newlines + 1
-		if parser.newlines == 0 && parser.mark.column > 1 {
-			foot_line++
-		}
-	}
-
-	var peek = 0
-	for ; peek < 512; peek++ {
-		if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
-			break
-		}
-		column++
-		if is_blank(parser.buffer, parser.buffer_pos+peek) {
-			continue
-		}
-		c := parser.buffer[parser.buffer_pos+peek]
-		var close_flow = parser.flow_level > 0 && (c == ']' || c == '}')
-		if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) {
-			// Got line break or terminator.
-			if close_flow || !recent_empty {
-				if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) {
-					// This is the first empty line and there were no empty lines before,
-					// so this initial part of the comment is a foot of the prior token
-					// instead of being a head for the following one. Split it up.
-					// Alternatively, this might also be the last comment inside a flow
-					// scope, so it must be a footer.
-					if len(text) > 0 {
-						if start_mark.column-1 < next_indent {
-							// If dedented it's unrelated to the prior token.
-							token_mark = start_mark
-						}
-						parser.comments = append(parser.comments, yaml_comment_t{
-							scan_mark:  scan_mark,
-							token_mark: token_mark,
-							start_mark: start_mark,
-							end_mark:   yaml_mark_t{parser.mark.index + peek, line, column},
-							foot:       text,
-						})
-						scan_mark = yaml_mark_t{parser.mark.index + peek, line, column}
-						token_mark = scan_mark
-						text = nil
-					}
-				} else {
-					if len(text) > 0 && parser.buffer[parser.buffer_pos+peek] != 0 {
-						text = append(text, '\n')
-					}
-				}
-			}
-			if !is_break(parser.buffer, parser.buffer_pos+peek) {
-				break
-			}
-			first_empty = false
-			recent_empty = true
-			column = 0
-			line++
-			continue
-		}
-
-		if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) {
-			// The comment at the different indentation is a foot of the
-			// preceding data rather than a head of the upcoming one.
-			parser.comments = append(parser.comments, yaml_comment_t{
-				scan_mark:  scan_mark,
-				token_mark: token_mark,
-				start_mark: start_mark,
-				end_mark:   yaml_mark_t{parser.mark.index + peek, line, column},
-				foot:       text,
-			})
-			scan_mark = yaml_mark_t{parser.mark.index + peek, line, column}
-			token_mark = scan_mark
-			text = nil
-		}
-
-		if parser.buffer[parser.buffer_pos+peek] != '#' {
-			break
-		}
-
-		if len(text) == 0 {
-			start_mark = yaml_mark_t{parser.mark.index + peek, line, column}
-		} else {
-			text = append(text, '\n')
-		}
-
-		recent_empty = false
-
-		// Consume until after the consumed comment line.
-		seen := parser.mark.index + peek
-		for {
-			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
-				return false
-			}
-			if is_breakz(parser.buffer, parser.buffer_pos) {
-				if parser.mark.index >= seen {
-					break
-				}
-				if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
-					return false
-				}
-				skip_line(parser)
-			} else if parser.mark.index >= seen {
-				text = read(parser, text)
-			} else {
-				skip(parser)
-			}
-		}
-
-		peek = 0
-		column = 0
-		line = parser.mark.line
-		next_indent = parser.indent
-		if next_indent < 0 {
-			next_indent = 0
-		}
-	}
-
-	if len(text) > 0 {
-		parser.comments = append(parser.comments, yaml_comment_t{
-			scan_mark:  scan_mark,
-			token_mark: start_mark,
-			start_mark: start_mark,
-			end_mark:   yaml_mark_t{parser.mark.index + peek - 1, line, column},
-			head:       text,
-		})
-	}
-	return true
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/sorter.go
@@ -1,134 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package yaml
-
-import (
-	"reflect"
-	"unicode"
-)
-
-type keyList []reflect.Value
-
-func (l keyList) Len() int      { return len(l) }
-func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
-func (l keyList) Less(i, j int) bool {
-	a := l[i]
-	b := l[j]
-	ak := a.Kind()
-	bk := b.Kind()
-	for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
-		a = a.Elem()
-		ak = a.Kind()
-	}
-	for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
-		b = b.Elem()
-		bk = b.Kind()
-	}
-	af, aok := keyFloat(a)
-	bf, bok := keyFloat(b)
-	if aok && bok {
-		if af != bf {
-			return af < bf
-		}
-		if ak != bk {
-			return ak < bk
-		}
-		return numLess(a, b)
-	}
-	if ak != reflect.String || bk != reflect.String {
-		return ak < bk
-	}
-	ar, br := []rune(a.String()), []rune(b.String())
-	digits := false
-	for i := 0; i < len(ar) && i < len(br); i++ {
-		if ar[i] == br[i] {
-			digits = unicode.IsDigit(ar[i])
-			continue
-		}
-		al := unicode.IsLetter(ar[i])
-		bl := unicode.IsLetter(br[i])
-		if al && bl {
-			return ar[i] < br[i]
-		}
-		if al || bl {
-			if digits {
-				return al
-			} else {
-				return bl
-			}
-		}
-		var ai, bi int
-		var an, bn int64
-		if ar[i] == '0' || br[i] == '0' {
-			for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
-				if ar[j] != '0' {
-					an = 1
-					bn = 1
-					break
-				}
-			}
-		}
-		for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
-			an = an*10 + int64(ar[ai]-'0')
-		}
-		for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
-			bn = bn*10 + int64(br[bi]-'0')
-		}
-		if an != bn {
-			return an < bn
-		}
-		if ai != bi {
-			return ai < bi
-		}
-		return ar[i] < br[i]
-	}
-	return len(ar) < len(br)
-}
-
-// keyFloat returns a float value for v if it is a number/bool
-// and whether it is a number/bool or not.
-func keyFloat(v reflect.Value) (f float64, ok bool) {
-	switch v.Kind() {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return float64(v.Int()), true
-	case reflect.Float32, reflect.Float64:
-		return v.Float(), true
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return float64(v.Uint()), true
-	case reflect.Bool:
-		if v.Bool() {
-			return 1, true
-		}
-		return 0, true
-	}
-	return 0, false
-}
-
-// numLess returns whether a < b.
-// a and b must necessarily have the same kind.
-func numLess(a, b reflect.Value) bool {
-	switch a.Kind() {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return a.Int() < b.Int()
-	case reflect.Float32, reflect.Float64:
-		return a.Float() < b.Float()
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return a.Uint() < b.Uint()
-	case reflect.Bool:
-		return !a.Bool() && b.Bool()
-	}
-	panic("not a number")
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/writerc.go
@@ -1,48 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-// Set the writer error and return false.
-func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
-	emitter.error = yaml_WRITER_ERROR
-	emitter.problem = problem
-	return false
-}
-
-// Flush the output buffer.
-func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
-	if emitter.write_handler == nil {
-		panic("write handler not set")
-	}
-
-	// Check if the buffer is empty.
-	if emitter.buffer_pos == 0 {
-		return true
-	}
-
-	if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
-		return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
-	}
-	emitter.buffer_pos = 0
-	return true
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/yaml.go
@@ -1,693 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package yaml implements YAML support for the Go language.
-//
-// Source code and other details for the project are available at GitHub:
-//
-//	https://github.com/go-yaml/yaml
-package yaml
-
-import (
-	"errors"
-	"fmt"
-	"io"
-	"reflect"
-	"strings"
-	"sync"
-	"unicode/utf8"
-)
-
-// The Unmarshaler interface may be implemented by types to customize their
-// behavior when being unmarshaled from a YAML document.
-type Unmarshaler interface {
-	UnmarshalYAML(value *Node) error
-}
-
-type obsoleteUnmarshaler interface {
-	UnmarshalYAML(unmarshal func(interface{}) error) error
-}
-
-// The Marshaler interface may be implemented by types to customize their
-// behavior when being marshaled into a YAML document. The returned value
-// is marshaled in place of the original value implementing Marshaler.
-//
-// If an error is returned by MarshalYAML, the marshaling procedure stops
-// and returns with the provided error.
-type Marshaler interface {
-	MarshalYAML() (interface{}, error)
-}
-
-// Unmarshal decodes the first document found within the in byte slice
-// and assigns decoded values into the out value.
-//
-// Maps and pointers (to a struct, string, int, etc) are accepted as out
-// values. If an internal pointer within a struct is not initialized,
-// the yaml package will initialize it if necessary for unmarshalling
-// the provided data. The out parameter must not be nil.
-//
-// The type of the decoded values should be compatible with the respective
-// values in out. If one or more values cannot be decoded due to a type
-// mismatches, decoding continues partially until the end of the YAML
-// content, and a *yaml.TypeError is returned with details for all
-// missed values.
-//
-// Struct fields are only unmarshalled if they are exported (have an
-// upper case first letter), and are unmarshalled using the field name
-// lowercased as the default key. Custom keys may be defined via the
-// "yaml" name in the field tag: the content preceding the first comma
-// is used as the key, and the following comma-separated options are
-// used to tweak the marshalling process (see Marshal).
-// Conflicting names result in a runtime error.
-//
-// For example:
-//
-//	type T struct {
-//	    F int `yaml:"a,omitempty"`
-//	    B int
-//	}
-//	var t T
-//	yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
-//
-// See the documentation of Marshal for the format of tags and a list of
-// supported tag options.
-func Unmarshal(in []byte, out interface{}) (err error) {
-	return unmarshal(in, out, false)
-}
-
-// A Decoder reads and decodes YAML values from an input stream.
-type Decoder struct {
-	parser      *parser
-	knownFields bool
-}
-
-// NewDecoder returns a new decoder that reads from r.
-//
-// The decoder introduces its own buffering and may read
-// data from r beyond the YAML values requested.
-func NewDecoder(r io.Reader) *Decoder {
-	return &Decoder{
-		parser: newParserFromReader(r),
-	}
-}
-
-// KnownFields ensures that the keys in decoded mappings to
-// exist as fields in the struct being decoded into.
-func (dec *Decoder) KnownFields(enable bool) {
-	dec.knownFields = enable
-}
-
-// Decode reads the next YAML-encoded value from its input
-// and stores it in the value pointed to by v.
-//
-// See the documentation for Unmarshal for details about the
-// conversion of YAML into a Go value.
-func (dec *Decoder) Decode(v interface{}) (err error) {
-	d := newDecoder()
-	d.knownFields = dec.knownFields
-	defer handleErr(&err)
-	node := dec.parser.parse()
-	if node == nil {
-		return io.EOF
-	}
-	out := reflect.ValueOf(v)
-	if out.Kind() == reflect.Ptr && !out.IsNil() {
-		out = out.Elem()
-	}
-	d.unmarshal(node, out)
-	if len(d.terrors) > 0 {
-		return &TypeError{d.terrors}
-	}
-	return nil
-}
-
-// Decode decodes the node and stores its data into the value pointed to by v.
-//
-// See the documentation for Unmarshal for details about the
-// conversion of YAML into a Go value.
-func (n *Node) Decode(v interface{}) (err error) {
-	d := newDecoder()
-	defer handleErr(&err)
-	out := reflect.ValueOf(v)
-	if out.Kind() == reflect.Ptr && !out.IsNil() {
-		out = out.Elem()
-	}
-	d.unmarshal(n, out)
-	if len(d.terrors) > 0 {
-		return &TypeError{d.terrors}
-	}
-	return nil
-}
-
-func unmarshal(in []byte, out interface{}, strict bool) (err error) {
-	defer handleErr(&err)
-	d := newDecoder()
-	p := newParser(in)
-	defer p.destroy()
-	node := p.parse()
-	if node != nil {
-		v := reflect.ValueOf(out)
-		if v.Kind() == reflect.Ptr && !v.IsNil() {
-			v = v.Elem()
-		}
-		d.unmarshal(node, v)
-	}
-	if len(d.terrors) > 0 {
-		return &TypeError{d.terrors}
-	}
-	return nil
-}
-
-// Marshal serializes the value provided into a YAML document. The structure
-// of the generated document will reflect the structure of the value itself.
-// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
-//
-// Struct fields are only marshalled if they are exported (have an upper case
-// first letter), and are marshalled using the field name lowercased as the
-// default key. Custom keys may be defined via the "yaml" name in the field
-// tag: the content preceding the first comma is used as the key, and the
-// following comma-separated options are used to tweak the marshalling process.
-// Conflicting names result in a runtime error.
-//
-// The field tag format accepted is:
-//
-//	`(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
-//
-// The following flags are currently supported:
-//
-//	omitempty    Only include the field if it's not set to the zero
-//	             value for the type or to empty slices or maps.
-//	             Zero valued structs will be omitted if all their public
-//	             fields are zero, unless they implement an IsZero
-//	             method (see the IsZeroer interface type), in which
-//	             case the field will be excluded if IsZero returns true.
-//
-//	flow         Marshal using a flow style (useful for structs,
-//	             sequences and maps).
-//
-//	inline       Inline the field, which must be a struct or a map,
-//	             causing all of its fields or keys to be processed as if
-//	             they were part of the outer struct. For maps, keys must
-//	             not conflict with the yaml keys of other struct fields.
-//
-// In addition, if the key is "-", the field is ignored.
-//
-// For example:
-//
-//	type T struct {
-//	    F int `yaml:"a,omitempty"`
-//	    B int
-//	}
-//	yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
-//	yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
-func Marshal(in interface{}) (out []byte, err error) {
-	defer handleErr(&err)
-	e := newEncoder()
-	defer e.destroy()
-	e.marshalDoc("", reflect.ValueOf(in))
-	e.finish()
-	out = e.out
-	return
-}
-
-// An Encoder writes YAML values to an output stream.
-type Encoder struct {
-	encoder *encoder
-}
-
-// NewEncoder returns a new encoder that writes to w.
-// The Encoder should be closed after use to flush all data
-// to w.
-func NewEncoder(w io.Writer) *Encoder {
-	return &Encoder{
-		encoder: newEncoderWithWriter(w),
-	}
-}
-
-// Encode writes the YAML encoding of v to the stream.
-// If multiple items are encoded to the stream, the
-// second and subsequent document will be preceded
-// with a "---" document separator, but the first will not.
-//
-// See the documentation for Marshal for details about the conversion of Go
-// values to YAML.
-func (e *Encoder) Encode(v interface{}) (err error) {
-	defer handleErr(&err)
-	e.encoder.marshalDoc("", reflect.ValueOf(v))
-	return nil
-}
-
-// Encode encodes value v and stores its representation in n.
-//
-// See the documentation for Marshal for details about the
-// conversion of Go values into YAML.
-func (n *Node) Encode(v interface{}) (err error) {
-	defer handleErr(&err)
-	e := newEncoder()
-	defer e.destroy()
-	e.marshalDoc("", reflect.ValueOf(v))
-	e.finish()
-	p := newParser(e.out)
-	p.textless = true
-	defer p.destroy()
-	doc := p.parse()
-	*n = *doc.Content[0]
-	return nil
-}
-
-// SetIndent changes the used indentation used when encoding.
-func (e *Encoder) SetIndent(spaces int) {
-	if spaces < 0 {
-		panic("yaml: cannot indent to a negative number of spaces")
-	}
-	e.encoder.indent = spaces
-}
-
-// Close closes the encoder by writing any remaining data.
-// It does not write a stream terminating string "...".
-func (e *Encoder) Close() (err error) {
-	defer handleErr(&err)
-	e.encoder.finish()
-	return nil
-}
-
-func handleErr(err *error) {
-	if v := recover(); v != nil {
-		if e, ok := v.(yamlError); ok {
-			*err = e.err
-		} else {
-			panic(v)
-		}
-	}
-}
-
-type yamlError struct {
-	err error
-}
-
-func fail(err error) {
-	panic(yamlError{err})
-}
-
-func failf(format string, args ...interface{}) {
-	panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
-}
-
-// A TypeError is returned by Unmarshal when one or more fields in
-// the YAML document cannot be properly decoded into the requested
-// types. When this error is returned, the value is still
-// unmarshaled partially.
-type TypeError struct {
-	Errors []string
-}
-
-func (e *TypeError) Error() string {
-	return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))
-}
-
-type Kind uint32
-
-const (
-	DocumentNode Kind = 1 << iota
-	SequenceNode
-	MappingNode
-	ScalarNode
-	AliasNode
-)
-
-type Style uint32
-
-const (
-	TaggedStyle Style = 1 << iota
-	DoubleQuotedStyle
-	SingleQuotedStyle
-	LiteralStyle
-	FoldedStyle
-	FlowStyle
-)
-
-// Node represents an element in the YAML document hierarchy. While documents
-// are typically encoded and decoded into higher level types, such as structs
-// and maps, Node is an intermediate representation that allows detailed
-// control over the content being decoded or encoded.
-//
-// It's worth noting that although Node offers access into details such as
-// line numbers, colums, and comments, the content when re-encoded will not
-// have its original textual representation preserved. An effort is made to
-// render the data plesantly, and to preserve comments near the data they
-// describe, though.
-//
-// Values that make use of the Node type interact with the yaml package in the
-// same way any other type would do, by encoding and decoding yaml data
-// directly or indirectly into them.
-//
-// For example:
-//
-//	var person struct {
-//	        Name    string
-//	        Address yaml.Node
-//	}
-//	err := yaml.Unmarshal(data, &person)
-//
-// Or by itself:
-//
-//	var person Node
-//	err := yaml.Unmarshal(data, &person)
-type Node struct {
-	// Kind defines whether the node is a document, a mapping, a sequence,
-	// a scalar value, or an alias to another node. The specific data type of
-	// scalar nodes may be obtained via the ShortTag and LongTag methods.
-	Kind Kind
-
-	// Style allows customizing the apperance of the node in the tree.
-	Style Style
-
-	// Tag holds the YAML tag defining the data type for the value.
-	// When decoding, this field will always be set to the resolved tag,
-	// even when it wasn't explicitly provided in the YAML content.
-	// When encoding, if this field is unset the value type will be
-	// implied from the node properties, and if it is set, it will only
-	// be serialized into the representation if TaggedStyle is used or
-	// the implicit tag diverges from the provided one.
-	Tag string
-
-	// Value holds the unescaped and unquoted represenation of the value.
-	Value string
-
-	// Anchor holds the anchor name for this node, which allows aliases to point to it.
-	Anchor string
-
-	// Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
-	Alias *Node
-
-	// Content holds contained nodes for documents, mappings, and sequences.
-	Content []*Node
-
-	// HeadComment holds any comments in the lines preceding the node and
-	// not separated by an empty line.
-	HeadComment string
-
-	// LineComment holds any comments at the end of the line where the node is in.
-	LineComment string
-
-	// FootComment holds any comments following the node and before empty lines.
-	FootComment string
-
-	// Line and Column hold the node position in the decoded YAML text.
-	// These fields are not respected when encoding the node.
-	Line   int
-	Column int
-}
-
-// IsZero returns whether the node has all of its fields unset.
-func (n *Node) IsZero() bool {
-	return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&
-		n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
-}
-
-// LongTag returns the long form of the tag that indicates the data type for
-// the node. If the Tag field isn't explicitly defined, one will be computed
-// based on the node properties.
-func (n *Node) LongTag() string {
-	return longTag(n.ShortTag())
-}
-
-// ShortTag returns the short form of the YAML tag that indicates data type for
-// the node. If the Tag field isn't explicitly defined, one will be computed
-// based on the node properties.
-func (n *Node) ShortTag() string {
-	if n.indicatedString() {
-		return strTag
-	}
-	if n.Tag == "" || n.Tag == "!" {
-		switch n.Kind {
-		case MappingNode:
-			return mapTag
-		case SequenceNode:
-			return seqTag
-		case AliasNode:
-			if n.Alias != nil {
-				return n.Alias.ShortTag()
-			}
-		case ScalarNode:
-			tag, _ := resolve("", n.Value)
-			return tag
-		case 0:
-			// Special case to make the zero value convenient.
-			if n.IsZero() {
-				return nullTag
-			}
-		}
-		return ""
-	}
-	return shortTag(n.Tag)
-}
-
-func (n *Node) indicatedString() bool {
-	return n.Kind == ScalarNode &&
-		(shortTag(n.Tag) == strTag ||
-			(n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
-}
-
-// SetString is a convenience function that sets the node to a string value
-// and defines its style in a pleasant way depending on its content.
-func (n *Node) SetString(s string) {
-	n.Kind = ScalarNode
-	if utf8.ValidString(s) {
-		n.Value = s
-		n.Tag = strTag
-	} else {
-		n.Value = encodeBase64(s)
-		n.Tag = binaryTag
-	}
-	if strings.Contains(n.Value, "\n") {
-		n.Style = LiteralStyle
-	}
-}
-
-// --------------------------------------------------------------------------
-// Maintain a mapping of keys to structure field indexes
-
-// The code in this section was copied from mgo/bson.
-
-// structInfo holds details for the serialization of fields of
-// a given struct.
-type structInfo struct {
-	FieldsMap  map[string]fieldInfo
-	FieldsList []fieldInfo
-
-	// InlineMap is the number of the field in the struct that
-	// contains an ,inline map, or -1 if there's none.
-	InlineMap int
-
-	// InlineUnmarshalers holds indexes to inlined fields that
-	// contain unmarshaler values.
-	InlineUnmarshalers [][]int
-}
-
-type fieldInfo struct {
-	Key       string
-	Num       int
-	OmitEmpty bool
-	Flow      bool
-	// Id holds the unique field identifier, so we can cheaply
-	// check for field duplicates without maintaining an extra map.
-	Id int
-
-	// Inline holds the field index if the field is part of an inlined struct.
-	Inline []int
-}
-
-var structMap = make(map[reflect.Type]*structInfo)
-var fieldMapMutex sync.RWMutex
-var unmarshalerType reflect.Type
-
-func init() {
-	var v Unmarshaler
-	unmarshalerType = reflect.ValueOf(&v).Elem().Type()
-}
-
-func getStructInfo(st reflect.Type) (*structInfo, error) {
-	fieldMapMutex.RLock()
-	sinfo, found := structMap[st]
-	fieldMapMutex.RUnlock()
-	if found {
-		return sinfo, nil
-	}
-
-	n := st.NumField()
-	fieldsMap := make(map[string]fieldInfo)
-	fieldsList := make([]fieldInfo, 0, n)
-	inlineMap := -1
-	inlineUnmarshalers := [][]int(nil)
-	for i := 0; i != n; i++ {
-		field := st.Field(i)
-		if field.PkgPath != "" && !field.Anonymous {
-			continue // Private field
-		}
-
-		info := fieldInfo{Num: i}
-
-		tag := field.Tag.Get("yaml")
-		if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
-			tag = string(field.Tag)
-		}
-		if tag == "-" {
-			continue
-		}
-
-		inline := false
-		fields := strings.Split(tag, ",")
-		if len(fields) > 1 {
-			for _, flag := range fields[1:] {
-				switch flag {
-				case "omitempty":
-					info.OmitEmpty = true
-				case "flow":
-					info.Flow = true
-				case "inline":
-					inline = true
-				default:
-					return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
-				}
-			}
-			tag = fields[0]
-		}
-
-		if inline {
-			switch field.Type.Kind() {
-			case reflect.Map:
-				if inlineMap >= 0 {
-					return nil, errors.New("multiple ,inline maps in struct " + st.String())
-				}
-				if field.Type.Key() != reflect.TypeOf("") {
-					return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
-				}
-				inlineMap = info.Num
-			case reflect.Struct, reflect.Ptr:
-				ftype := field.Type
-				for ftype.Kind() == reflect.Ptr {
-					ftype = ftype.Elem()
-				}
-				if ftype.Kind() != reflect.Struct {
-					return nil, errors.New("option ,inline may only be used on a struct or map field")
-				}
-				if reflect.PtrTo(ftype).Implements(unmarshalerType) {
-					inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
-				} else {
-					sinfo, err := getStructInfo(ftype)
-					if err != nil {
-						return nil, err
-					}
-					for _, index := range sinfo.InlineUnmarshalers {
-						inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
-					}
-					for _, finfo := range sinfo.FieldsList {
-						if _, found := fieldsMap[finfo.Key]; found {
-							msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
-							return nil, errors.New(msg)
-						}
-						if finfo.Inline == nil {
-							finfo.Inline = []int{i, finfo.Num}
-						} else {
-							finfo.Inline = append([]int{i}, finfo.Inline...)
-						}
-						finfo.Id = len(fieldsList)
-						fieldsMap[finfo.Key] = finfo
-						fieldsList = append(fieldsList, finfo)
-					}
-				}
-			default:
-				return nil, errors.New("option ,inline may only be used on a struct or map field")
-			}
-			continue
-		}
-
-		if tag != "" {
-			info.Key = tag
-		} else {
-			info.Key = strings.ToLower(field.Name)
-		}
-
-		if _, found = fieldsMap[info.Key]; found {
-			msg := "duplicated key '" + info.Key + "' in struct " + st.String()
-			return nil, errors.New(msg)
-		}
-
-		info.Id = len(fieldsList)
-		fieldsList = append(fieldsList, info)
-		fieldsMap[info.Key] = info
-	}
-
-	sinfo = &structInfo{
-		FieldsMap:          fieldsMap,
-		FieldsList:         fieldsList,
-		InlineMap:          inlineMap,
-		InlineUnmarshalers: inlineUnmarshalers,
-	}
-
-	fieldMapMutex.Lock()
-	structMap[st] = sinfo
-	fieldMapMutex.Unlock()
-	return sinfo, nil
-}
-
-// IsZeroer is used to check whether an object is zero to
-// determine whether it should be omitted when marshaling
-// with the omitempty flag. One notable implementation
-// is time.Time.
-type IsZeroer interface {
-	IsZero() bool
-}
-
-func isZero(v reflect.Value) bool {
-	kind := v.Kind()
-	if z, ok := v.Interface().(IsZeroer); ok {
-		if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
-			return true
-		}
-		return z.IsZero()
-	}
-	switch kind {
-	case reflect.String:
-		return len(v.String()) == 0
-	case reflect.Interface, reflect.Ptr:
-		return v.IsNil()
-	case reflect.Slice:
-		return v.Len() == 0
-	case reflect.Map:
-		return v.Len() == 0
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return v.Int() == 0
-	case reflect.Float32, reflect.Float64:
-		return v.Float() == 0
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return v.Uint() == 0
-	case reflect.Bool:
-		return !v.Bool()
-	case reflect.Struct:
-		vt := v.Type()
-		for i := v.NumField() - 1; i >= 0; i-- {
-			if vt.Field(i).PkgPath != "" {
-				continue // Private field
-			}
-			if !isZero(v.Field(i)) {
-				return false
-			}
-		}
-		return true
-	}
-	return false
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/yamlh.go
@@ -1,809 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-import (
-	"fmt"
-	"io"
-)
-
-// The version directive data.
-type yaml_version_directive_t struct {
-	major int8 // The major version number.
-	minor int8 // The minor version number.
-}
-
-// The tag directive data.
-type yaml_tag_directive_t struct {
-	handle []byte // The tag handle.
-	prefix []byte // The tag prefix.
-}
-
-type yaml_encoding_t int
-
-// The stream encoding.
-const (
-	// Let the parser choose the encoding.
-	yaml_ANY_ENCODING yaml_encoding_t = iota
-
-	yaml_UTF8_ENCODING    // The default UTF-8 encoding.
-	yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
-	yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
-)
-
-type yaml_break_t int
-
-// Line break types.
-const (
-	// Let the parser choose the break type.
-	yaml_ANY_BREAK yaml_break_t = iota
-
-	yaml_CR_BREAK   // Use CR for line breaks (Mac style).
-	yaml_LN_BREAK   // Use LN for line breaks (Unix style).
-	yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
-)
-
-type yaml_error_type_t int
-
-// Many bad things could happen with the parser and emitter.
-const (
-	// No error is produced.
-	yaml_NO_ERROR yaml_error_type_t = iota
-
-	yaml_MEMORY_ERROR   // Cannot allocate or reallocate a block of memory.
-	yaml_READER_ERROR   // Cannot read or decode the input stream.
-	yaml_SCANNER_ERROR  // Cannot scan the input stream.
-	yaml_PARSER_ERROR   // Cannot parse the input stream.
-	yaml_COMPOSER_ERROR // Cannot compose a YAML document.
-	yaml_WRITER_ERROR   // Cannot write to the output stream.
-	yaml_EMITTER_ERROR  // Cannot emit a YAML stream.
-)
-
-// The pointer position.
-type yaml_mark_t struct {
-	index  int // The position index.
-	line   int // The position line.
-	column int // The position column.
-}
-
-// Node Styles
-
-type yaml_style_t int8
-
-type yaml_scalar_style_t yaml_style_t
-
-// Scalar styles.
-const (
-	// Let the emitter choose the style.
-	yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0
-
-	yaml_PLAIN_SCALAR_STYLE         yaml_scalar_style_t = 1 << iota // The plain scalar style.
-	yaml_SINGLE_QUOTED_SCALAR_STYLE                                 // The single-quoted scalar style.
-	yaml_DOUBLE_QUOTED_SCALAR_STYLE                                 // The double-quoted scalar style.
-	yaml_LITERAL_SCALAR_STYLE                                       // The literal scalar style.
-	yaml_FOLDED_SCALAR_STYLE                                        // The folded scalar style.
-)
-
-type yaml_sequence_style_t yaml_style_t
-
-// Sequence styles.
-const (
-	// Let the emitter choose the style.
-	yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
-
-	yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
-	yaml_FLOW_SEQUENCE_STYLE  // The flow sequence style.
-)
-
-type yaml_mapping_style_t yaml_style_t
-
-// Mapping styles.
-const (
-	// Let the emitter choose the style.
-	yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
-
-	yaml_BLOCK_MAPPING_STYLE // The block mapping style.
-	yaml_FLOW_MAPPING_STYLE  // The flow mapping style.
-)
-
-// Tokens
-
-type yaml_token_type_t int
-
-// Token types.
-const (
-	// An empty token.
-	yaml_NO_TOKEN yaml_token_type_t = iota
-
-	yaml_STREAM_START_TOKEN // A STREAM-START token.
-	yaml_STREAM_END_TOKEN   // A STREAM-END token.
-
-	yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
-	yaml_TAG_DIRECTIVE_TOKEN     // A TAG-DIRECTIVE token.
-	yaml_DOCUMENT_START_TOKEN    // A DOCUMENT-START token.
-	yaml_DOCUMENT_END_TOKEN      // A DOCUMENT-END token.
-
-	yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
-	yaml_BLOCK_MAPPING_START_TOKEN  // A BLOCK-SEQUENCE-END token.
-	yaml_BLOCK_END_TOKEN            // A BLOCK-END token.
-
-	yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
-	yaml_FLOW_SEQUENCE_END_TOKEN   // A FLOW-SEQUENCE-END token.
-	yaml_FLOW_MAPPING_START_TOKEN  // A FLOW-MAPPING-START token.
-	yaml_FLOW_MAPPING_END_TOKEN    // A FLOW-MAPPING-END token.
-
-	yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
-	yaml_FLOW_ENTRY_TOKEN  // A FLOW-ENTRY token.
-	yaml_KEY_TOKEN         // A KEY token.
-	yaml_VALUE_TOKEN       // A VALUE token.
-
-	yaml_ALIAS_TOKEN  // An ALIAS token.
-	yaml_ANCHOR_TOKEN // An ANCHOR token.
-	yaml_TAG_TOKEN    // A TAG token.
-	yaml_SCALAR_TOKEN // A SCALAR token.
-)
-
-func (tt yaml_token_type_t) String() string {
-	switch tt {
-	case yaml_NO_TOKEN:
-		return "yaml_NO_TOKEN"
-	case yaml_STREAM_START_TOKEN:
-		return "yaml_STREAM_START_TOKEN"
-	case yaml_STREAM_END_TOKEN:
-		return "yaml_STREAM_END_TOKEN"
-	case yaml_VERSION_DIRECTIVE_TOKEN:
-		return "yaml_VERSION_DIRECTIVE_TOKEN"
-	case yaml_TAG_DIRECTIVE_TOKEN:
-		return "yaml_TAG_DIRECTIVE_TOKEN"
-	case yaml_DOCUMENT_START_TOKEN:
-		return "yaml_DOCUMENT_START_TOKEN"
-	case yaml_DOCUMENT_END_TOKEN:
-		return "yaml_DOCUMENT_END_TOKEN"
-	case yaml_BLOCK_SEQUENCE_START_TOKEN:
-		return "yaml_BLOCK_SEQUENCE_START_TOKEN"
-	case yaml_BLOCK_MAPPING_START_TOKEN:
-		return "yaml_BLOCK_MAPPING_START_TOKEN"
-	case yaml_BLOCK_END_TOKEN:
-		return "yaml_BLOCK_END_TOKEN"
-	case yaml_FLOW_SEQUENCE_START_TOKEN:
-		return "yaml_FLOW_SEQUENCE_START_TOKEN"
-	case yaml_FLOW_SEQUENCE_END_TOKEN:
-		return "yaml_FLOW_SEQUENCE_END_TOKEN"
-	case yaml_FLOW_MAPPING_START_TOKEN:
-		return "yaml_FLOW_MAPPING_START_TOKEN"
-	case yaml_FLOW_MAPPING_END_TOKEN:
-		return "yaml_FLOW_MAPPING_END_TOKEN"
-	case yaml_BLOCK_ENTRY_TOKEN:
-		return "yaml_BLOCK_ENTRY_TOKEN"
-	case yaml_FLOW_ENTRY_TOKEN:
-		return "yaml_FLOW_ENTRY_TOKEN"
-	case yaml_KEY_TOKEN:
-		return "yaml_KEY_TOKEN"
-	case yaml_VALUE_TOKEN:
-		return "yaml_VALUE_TOKEN"
-	case yaml_ALIAS_TOKEN:
-		return "yaml_ALIAS_TOKEN"
-	case yaml_ANCHOR_TOKEN:
-		return "yaml_ANCHOR_TOKEN"
-	case yaml_TAG_TOKEN:
-		return "yaml_TAG_TOKEN"
-	case yaml_SCALAR_TOKEN:
-		return "yaml_SCALAR_TOKEN"
-	}
-	return "<unknown token>"
-}
-
-// The token structure.
-type yaml_token_t struct {
-	// The token type.
-	typ yaml_token_type_t
-
-	// The start/end of the token.
-	start_mark, end_mark yaml_mark_t
-
-	// The stream encoding (for yaml_STREAM_START_TOKEN).
-	encoding yaml_encoding_t
-
-	// The alias/anchor/scalar value or tag/tag directive handle
-	// (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
-	value []byte
-
-	// The tag suffix (for yaml_TAG_TOKEN).
-	suffix []byte
-
-	// The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
-	prefix []byte
-
-	// The scalar style (for yaml_SCALAR_TOKEN).
-	style yaml_scalar_style_t
-
-	// The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
-	major, minor int8
-}
-
-// Events
-
-type yaml_event_type_t int8
-
-// Event types.
-const (
-	// An empty event.
-	yaml_NO_EVENT yaml_event_type_t = iota
-
-	yaml_STREAM_START_EVENT   // A STREAM-START event.
-	yaml_STREAM_END_EVENT     // A STREAM-END event.
-	yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
-	yaml_DOCUMENT_END_EVENT   // A DOCUMENT-END event.
-	yaml_ALIAS_EVENT          // An ALIAS event.
-	yaml_SCALAR_EVENT         // A SCALAR event.
-	yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
-	yaml_SEQUENCE_END_EVENT   // A SEQUENCE-END event.
-	yaml_MAPPING_START_EVENT  // A MAPPING-START event.
-	yaml_MAPPING_END_EVENT    // A MAPPING-END event.
-	yaml_TAIL_COMMENT_EVENT
-)
-
-var eventStrings = []string{
-	yaml_NO_EVENT:             "none",
-	yaml_STREAM_START_EVENT:   "stream start",
-	yaml_STREAM_END_EVENT:     "stream end",
-	yaml_DOCUMENT_START_EVENT: "document start",
-	yaml_DOCUMENT_END_EVENT:   "document end",
-	yaml_ALIAS_EVENT:          "alias",
-	yaml_SCALAR_EVENT:         "scalar",
-	yaml_SEQUENCE_START_EVENT: "sequence start",
-	yaml_SEQUENCE_END_EVENT:   "sequence end",
-	yaml_MAPPING_START_EVENT:  "mapping start",
-	yaml_MAPPING_END_EVENT:    "mapping end",
-	yaml_TAIL_COMMENT_EVENT:   "tail comment",
-}
-
-func (e yaml_event_type_t) String() string {
-	if e < 0 || int(e) >= len(eventStrings) {
-		return fmt.Sprintf("unknown event %d", e)
-	}
-	return eventStrings[e]
-}
-
-// The event structure.
-type yaml_event_t struct {
-
-	// The event type.
-	typ yaml_event_type_t
-
-	// The start and end of the event.
-	start_mark, end_mark yaml_mark_t
-
-	// The document encoding (for yaml_STREAM_START_EVENT).
-	encoding yaml_encoding_t
-
-	// The version directive (for yaml_DOCUMENT_START_EVENT).
-	version_directive *yaml_version_directive_t
-
-	// The list of tag directives (for yaml_DOCUMENT_START_EVENT).
-	tag_directives []yaml_tag_directive_t
-
-	// The comments
-	head_comment []byte
-	line_comment []byte
-	foot_comment []byte
-	tail_comment []byte
-
-	// The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
-	anchor []byte
-
-	// The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
-	tag []byte
-
-	// The scalar value (for yaml_SCALAR_EVENT).
-	value []byte
-
-	// Is the document start/end indicator implicit, or the tag optional?
-	// (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
-	implicit bool
-
-	// Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
-	quoted_implicit bool
-
-	// The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
-	style yaml_style_t
-}
-
-func (e *yaml_event_t) scalar_style() yaml_scalar_style_t     { return yaml_scalar_style_t(e.style) }
-func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
-func (e *yaml_event_t) mapping_style() yaml_mapping_style_t   { return yaml_mapping_style_t(e.style) }
-
-// Nodes
-
-const (
-	yaml_NULL_TAG      = "tag:yaml.org,2002:null"      // The tag !!null with the only possible value: null.
-	yaml_BOOL_TAG      = "tag:yaml.org,2002:bool"      // The tag !!bool with the values: true and false.
-	yaml_STR_TAG       = "tag:yaml.org,2002:str"       // The tag !!str for string values.
-	yaml_INT_TAG       = "tag:yaml.org,2002:int"       // The tag !!int for integer values.
-	yaml_FLOAT_TAG     = "tag:yaml.org,2002:float"     // The tag !!float for float values.
-	yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
-
-	yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
-	yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
-
-	// Not in original libyaml.
-	yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
-	yaml_MERGE_TAG  = "tag:yaml.org,2002:merge"
-
-	yaml_DEFAULT_SCALAR_TAG   = yaml_STR_TAG // The default scalar tag is !!str.
-	yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
-	yaml_DEFAULT_MAPPING_TAG  = yaml_MAP_TAG // The default mapping tag is !!map.
-)
-
-type yaml_node_type_t int
-
-// Node types.
-const (
-	// An empty node.
-	yaml_NO_NODE yaml_node_type_t = iota
-
-	yaml_SCALAR_NODE   // A scalar node.
-	yaml_SEQUENCE_NODE // A sequence node.
-	yaml_MAPPING_NODE  // A mapping node.
-)
-
-// An element of a sequence node.
-type yaml_node_item_t int
-
-// An element of a mapping node.
-type yaml_node_pair_t struct {
-	key   int // The key of the element.
-	value int // The value of the element.
-}
-
-// The node structure.
-type yaml_node_t struct {
-	typ yaml_node_type_t // The node type.
-	tag []byte           // The node tag.
-
-	// The node data.
-
-	// The scalar parameters (for yaml_SCALAR_NODE).
-	scalar struct {
-		value  []byte              // The scalar value.
-		length int                 // The length of the scalar value.
-		style  yaml_scalar_style_t // The scalar style.
-	}
-
-	// The sequence parameters (for YAML_SEQUENCE_NODE).
-	sequence struct {
-		items_data []yaml_node_item_t    // The stack of sequence items.
-		style      yaml_sequence_style_t // The sequence style.
-	}
-
-	// The mapping parameters (for yaml_MAPPING_NODE).
-	mapping struct {
-		pairs_data  []yaml_node_pair_t   // The stack of mapping pairs (key, value).
-		pairs_start *yaml_node_pair_t    // The beginning of the stack.
-		pairs_end   *yaml_node_pair_t    // The end of the stack.
-		pairs_top   *yaml_node_pair_t    // The top of the stack.
-		style       yaml_mapping_style_t // The mapping style.
-	}
-
-	start_mark yaml_mark_t // The beginning of the node.
-	end_mark   yaml_mark_t // The end of the node.
-
-}
-
-// The document structure.
-type yaml_document_t struct {
-
-	// The document nodes.
-	nodes []yaml_node_t
-
-	// The version directive.
-	version_directive *yaml_version_directive_t
-
-	// The list of tag directives.
-	tag_directives_data  []yaml_tag_directive_t
-	tag_directives_start int // The beginning of the tag directives list.
-	tag_directives_end   int // The end of the tag directives list.
-
-	start_implicit int // Is the document start indicator implicit?
-	end_implicit   int // Is the document end indicator implicit?
-
-	// The start/end of the document.
-	start_mark, end_mark yaml_mark_t
-}
-
-// The prototype of a read handler.
-//
-// The read handler is called when the parser needs to read more bytes from the
-// source. The handler should write not more than size bytes to the buffer.
-// The number of written bytes should be set to the size_read variable.
-//
-// [in,out]   data        A pointer to an application data specified by
-//
-//	yaml_parser_set_input().
-//
-// [out]      buffer      The buffer to write the data from the source.
-// [in]       size        The size of the buffer.
-// [out]      size_read   The actual number of bytes read from the source.
-//
-// On success, the handler should return 1.  If the handler failed,
-// the returned value should be 0. On EOF, the handler should set the
-// size_read to 0 and return 1.
-type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
-
-// This structure holds information about a potential simple key.
-type yaml_simple_key_t struct {
-	possible     bool        // Is a simple key possible?
-	required     bool        // Is a simple key required?
-	token_number int         // The number of the token.
-	mark         yaml_mark_t // The position mark.
-}
-
-// The states of the parser.
-type yaml_parser_state_t int
-
-const (
-	yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
-
-	yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE           // Expect the beginning of an implicit document.
-	yaml_PARSE_DOCUMENT_START_STATE                    // Expect DOCUMENT-START.
-	yaml_PARSE_DOCUMENT_CONTENT_STATE                  // Expect the content of a document.
-	yaml_PARSE_DOCUMENT_END_STATE                      // Expect DOCUMENT-END.
-	yaml_PARSE_BLOCK_NODE_STATE                        // Expect a block node.
-	yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
-	yaml_PARSE_FLOW_NODE_STATE                         // Expect a flow node.
-	yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE        // Expect the first entry of a block sequence.
-	yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE              // Expect an entry of a block sequence.
-	yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE         // Expect an entry of an indentless sequence.
-	yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE           // Expect the first key of a block mapping.
-	yaml_PARSE_BLOCK_MAPPING_KEY_STATE                 // Expect a block mapping key.
-	yaml_PARSE_BLOCK_MAPPING_VALUE_STATE               // Expect a block mapping value.
-	yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE         // Expect the first entry of a flow sequence.
-	yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE               // Expect an entry of a flow sequence.
-	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE   // Expect a key of an ordered mapping.
-	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
-	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE   // Expect the and of an ordered mapping entry.
-	yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE            // Expect the first key of a flow mapping.
-	yaml_PARSE_FLOW_MAPPING_KEY_STATE                  // Expect a key of a flow mapping.
-	yaml_PARSE_FLOW_MAPPING_VALUE_STATE                // Expect a value of a flow mapping.
-	yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE          // Expect an empty value of a flow mapping.
-	yaml_PARSE_END_STATE                               // Expect nothing.
-)
-
-func (ps yaml_parser_state_t) String() string {
-	switch ps {
-	case yaml_PARSE_STREAM_START_STATE:
-		return "yaml_PARSE_STREAM_START_STATE"
-	case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
-		return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
-	case yaml_PARSE_DOCUMENT_START_STATE:
-		return "yaml_PARSE_DOCUMENT_START_STATE"
-	case yaml_PARSE_DOCUMENT_CONTENT_STATE:
-		return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
-	case yaml_PARSE_DOCUMENT_END_STATE:
-		return "yaml_PARSE_DOCUMENT_END_STATE"
-	case yaml_PARSE_BLOCK_NODE_STATE:
-		return "yaml_PARSE_BLOCK_NODE_STATE"
-	case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
-		return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
-	case yaml_PARSE_FLOW_NODE_STATE:
-		return "yaml_PARSE_FLOW_NODE_STATE"
-	case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
-		return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
-	case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
-		return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
-	case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
-		return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
-	case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
-		return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
-	case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
-		return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
-	case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
-		return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
-	case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
-		return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
-	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
-		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
-	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
-		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
-	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
-		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
-	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
-		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
-	case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
-		return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
-	case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
-		return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
-	case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
-		return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
-	case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
-		return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
-	case yaml_PARSE_END_STATE:
-		return "yaml_PARSE_END_STATE"
-	}
-	return "<unknown parser state>"
-}
-
-// This structure holds aliases data.
-type yaml_alias_data_t struct {
-	anchor []byte      // The anchor.
-	index  int         // The node id.
-	mark   yaml_mark_t // The anchor mark.
-}
-
-// The parser structure.
-//
-// All members are internal. Manage the structure using the
-// yaml_parser_ family of functions.
-type yaml_parser_t struct {
-
-	// Error handling
-
-	error yaml_error_type_t // Error type.
-
-	problem string // Error description.
-
-	// The byte about which the problem occurred.
-	problem_offset int
-	problem_value  int
-	problem_mark   yaml_mark_t
-
-	// The error context.
-	context      string
-	context_mark yaml_mark_t
-
-	// Reader stuff
-
-	read_handler yaml_read_handler_t // Read handler.
-
-	input_reader io.Reader // File input data.
-	input        []byte    // String input data.
-	input_pos    int
-
-	eof bool // EOF flag
-
-	buffer     []byte // The working buffer.
-	buffer_pos int    // The current position of the buffer.
-
-	unread int // The number of unread characters in the buffer.
-
-	newlines int // The number of line breaks since last non-break/non-blank character
-
-	raw_buffer     []byte // The raw buffer.
-	raw_buffer_pos int    // The current position of the buffer.
-
-	encoding yaml_encoding_t // The input encoding.
-
-	offset int         // The offset of the current position (in bytes).
-	mark   yaml_mark_t // The mark of the current position.
-
-	// Comments
-
-	head_comment []byte // The current head comments
-	line_comment []byte // The current line comments
-	foot_comment []byte // The current foot comments
-	tail_comment []byte // Foot comment that happens at the end of a block.
-	stem_comment []byte // Comment in item preceding a nested structure (list inside list item, etc)
-
-	comments      []yaml_comment_t // The folded comments for all parsed tokens
-	comments_head int
-
-	// Scanner stuff
-
-	stream_start_produced bool // Have we started to scan the input stream?
-	stream_end_produced   bool // Have we reached the end of the input stream?
-
-	flow_level int // The number of unclosed '[' and '{' indicators.
-
-	tokens          []yaml_token_t // The tokens queue.
-	tokens_head     int            // The head of the tokens queue.
-	tokens_parsed   int            // The number of tokens fetched from the queue.
-	token_available bool           // Does the tokens queue contain a token ready for dequeueing.
-
-	indent  int   // The current indentation level.
-	indents []int // The indentation levels stack.
-
-	simple_key_allowed bool                // May a simple key occur at the current position?
-	simple_keys        []yaml_simple_key_t // The stack of simple keys.
-	simple_keys_by_tok map[int]int         // possible simple_key indexes indexed by token_number
-
-	// Parser stuff
-
-	state          yaml_parser_state_t    // The current parser state.
-	states         []yaml_parser_state_t  // The parser states stack.
-	marks          []yaml_mark_t          // The stack of marks.
-	tag_directives []yaml_tag_directive_t // The list of TAG directives.
-
-	// Dumper stuff
-
-	aliases []yaml_alias_data_t // The alias data.
-
-	document *yaml_document_t // The currently parsed document.
-}
-
-type yaml_comment_t struct {
-	scan_mark  yaml_mark_t // Position where scanning for comments started
-	token_mark yaml_mark_t // Position after which tokens will be associated with this comment
-	start_mark yaml_mark_t // Position of '#' comment mark
-	end_mark   yaml_mark_t // Position where comment terminated
-
-	head []byte
-	line []byte
-	foot []byte
-}
-
-// Emitter Definitions
-
-// The prototype of a write handler.
-//
-// The write handler is called when the emitter needs to flush the accumulated
-// characters to the output.  The handler should write @a size bytes of the
-// @a buffer to the output.
-//
-// @param[in,out]   data        A pointer to an application data specified by
-//
-//	yaml_emitter_set_output().
-//
-// @param[in]       buffer      The buffer with bytes to be written.
-// @param[in]       size        The size of the buffer.
-//
-// @returns On success, the handler should return @c 1.  If the handler failed,
-// the returned value should be @c 0.
-type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
-
-type yaml_emitter_state_t int
-
-// The emitter states.
-const (
-	// Expect STREAM-START.
-	yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
-
-	yaml_EMIT_FIRST_DOCUMENT_START_STATE       // Expect the first DOCUMENT-START or STREAM-END.
-	yaml_EMIT_DOCUMENT_START_STATE             // Expect DOCUMENT-START or STREAM-END.
-	yaml_EMIT_DOCUMENT_CONTENT_STATE           // Expect the content of a document.
-	yaml_EMIT_DOCUMENT_END_STATE               // Expect DOCUMENT-END.
-	yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE   // Expect the first item of a flow sequence.
-	yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE   // Expect the next item of a flow sequence, with the comma already written out
-	yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE         // Expect an item of a flow sequence.
-	yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE     // Expect the first key of a flow mapping.
-	yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE     // Expect the next key of a flow mapping, with the comma already written out
-	yaml_EMIT_FLOW_MAPPING_KEY_STATE           // Expect a key of a flow mapping.
-	yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE  // Expect a value for a simple key of a flow mapping.
-	yaml_EMIT_FLOW_MAPPING_VALUE_STATE         // Expect a value of a flow mapping.
-	yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE  // Expect the first item of a block sequence.
-	yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE        // Expect an item of a block sequence.
-	yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE    // Expect the first key of a block mapping.
-	yaml_EMIT_BLOCK_MAPPING_KEY_STATE          // Expect the key of a block mapping.
-	yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
-	yaml_EMIT_BLOCK_MAPPING_VALUE_STATE        // Expect a value of a block mapping.
-	yaml_EMIT_END_STATE                        // Expect nothing.
-)
-
-// The emitter structure.
-//
-// All members are internal.  Manage the structure using the @c yaml_emitter_
-// family of functions.
-type yaml_emitter_t struct {
-
-	// Error handling
-
-	error   yaml_error_type_t // Error type.
-	problem string            // Error description.
-
-	// Writer stuff
-
-	write_handler yaml_write_handler_t // Write handler.
-
-	output_buffer *[]byte   // String output data.
-	output_writer io.Writer // File output data.
-
-	buffer     []byte // The working buffer.
-	buffer_pos int    // The current position of the buffer.
-
-	raw_buffer     []byte // The raw buffer.
-	raw_buffer_pos int    // The current position of the buffer.
-
-	encoding yaml_encoding_t // The stream encoding.
-
-	// Emitter stuff
-
-	canonical   bool         // If the output is in the canonical style?
-	best_indent int          // The number of indentation spaces.
-	best_width  int          // The preferred width of the output lines.
-	unicode     bool         // Allow unescaped non-ASCII characters?
-	line_break  yaml_break_t // The preferred line break.
-
-	state  yaml_emitter_state_t   // The current emitter state.
-	states []yaml_emitter_state_t // The stack of states.
-
-	events      []yaml_event_t // The event queue.
-	events_head int            // The head of the event queue.
-
-	indents []int // The stack of indentation levels.
-
-	tag_directives []yaml_tag_directive_t // The list of tag directives.
-
-	indent int // The current indentation level.
-
-	flow_level int // The current flow level.
-
-	root_context       bool // Is it the document root context?
-	sequence_context   bool // Is it a sequence context?
-	mapping_context    bool // Is it a mapping context?
-	simple_key_context bool // Is it a simple mapping key context?
-
-	line       int  // The current line.
-	column     int  // The current column.
-	whitespace bool // If the last character was a whitespace?
-	indention  bool // If the last character was an indentation character (' ', '-', '?', ':')?
-	open_ended bool // If an explicit document end is required?
-
-	space_above bool // Is there's an empty line above?
-	foot_indent int  // The indent used to write the foot comment above, or -1 if none.
-
-	// Anchor analysis.
-	anchor_data struct {
-		anchor []byte // The anchor value.
-		alias  bool   // Is it an alias?
-	}
-
-	// Tag analysis.
-	tag_data struct {
-		handle []byte // The tag handle.
-		suffix []byte // The tag suffix.
-	}
-
-	// Scalar analysis.
-	scalar_data struct {
-		value                 []byte              // The scalar value.
-		multiline             bool                // Does the scalar contain line breaks?
-		flow_plain_allowed    bool                // Can the scalar be expessed in the flow plain style?
-		block_plain_allowed   bool                // Can the scalar be expressed in the block plain style?
-		single_quoted_allowed bool                // Can the scalar be expressed in the single quoted style?
-		block_allowed         bool                // Can the scalar be expressed in the literal or folded styles?
-		style                 yaml_scalar_style_t // The output style.
-	}
-
-	// Comments
-	head_comment []byte
-	line_comment []byte
-	foot_comment []byte
-	tail_comment []byte
-
-	key_line_comment []byte
-
-	// Dumper stuff
-
-	opened bool // If the stream was already opened?
-	closed bool // If the stream was already closed?
-
-	// The information associated with the document nodes.
-	anchors *struct {
-		references int  // The number of references.
-		anchor     int  // The anchor id.
-		serialized bool // If the node has been emitted?
-	}
-
-	last_anchor_id int // The last assigned anchor id.
-
-	document *yaml_document_t // The currently emitted document.
-}
tools/review-tool/vendor/gopkg.in/yaml.v3/yamlprivateh.go
@@ -1,198 +0,0 @@
-//
-// Copyright (c) 2011-2019 Canonical Ltd
-// Copyright (c) 2006-2010 Kirill Simonov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-// of the Software, and to permit persons to whom the Software is furnished to do
-// so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-package yaml
-
-const (
-	// The size of the input raw buffer.
-	input_raw_buffer_size = 512
-
-	// The size of the input buffer.
-	// It should be possible to decode the whole raw buffer.
-	input_buffer_size = input_raw_buffer_size * 3
-
-	// The size of the output buffer.
-	output_buffer_size = 128
-
-	// The size of the output raw buffer.
-	// It should be possible to encode the whole output buffer.
-	output_raw_buffer_size = (output_buffer_size*2 + 2)
-
-	// The size of other stacks and queues.
-	initial_stack_size  = 16
-	initial_queue_size  = 16
-	initial_string_size = 16
-)
-
-// Check if the character at the specified position is an alphabetical
-// character, a digit, '_', or '-'.
-func is_alpha(b []byte, i int) bool {
-	return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
-}
-
-// Check if the character at the specified position is a digit.
-func is_digit(b []byte, i int) bool {
-	return b[i] >= '0' && b[i] <= '9'
-}
-
-// Get the value of a digit.
-func as_digit(b []byte, i int) int {
-	return int(b[i]) - '0'
-}
-
-// Check if the character at the specified position is a hex-digit.
-func is_hex(b []byte, i int) bool {
-	return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
-}
-
-// Get the value of a hex-digit.
-func as_hex(b []byte, i int) int {
-	bi := b[i]
-	if bi >= 'A' && bi <= 'F' {
-		return int(bi) - 'A' + 10
-	}
-	if bi >= 'a' && bi <= 'f' {
-		return int(bi) - 'a' + 10
-	}
-	return int(bi) - '0'
-}
-
-// Check if the character is ASCII.
-func is_ascii(b []byte, i int) bool {
-	return b[i] <= 0x7F
-}
-
-// Check if the character at the start of the buffer can be printed unescaped.
-func is_printable(b []byte, i int) bool {
-	return ((b[i] == 0x0A) || // . == #x0A
-		(b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
-		(b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
-		(b[i] > 0xC2 && b[i] < 0xED) ||
-		(b[i] == 0xED && b[i+1] < 0xA0) ||
-		(b[i] == 0xEE) ||
-		(b[i] == 0xEF && // #xE000 <= . <= #xFFFD
-			!(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
-			!(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
-}
-
-// Check if the character at the specified position is NUL.
-func is_z(b []byte, i int) bool {
-	return b[i] == 0x00
-}
-
-// Check if the beginning of the buffer is a BOM.
-func is_bom(b []byte, i int) bool {
-	return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
-}
-
-// Check if the character at the specified position is space.
-func is_space(b []byte, i int) bool {
-	return b[i] == ' '
-}
-
-// Check if the character at the specified position is tab.
-func is_tab(b []byte, i int) bool {
-	return b[i] == '\t'
-}
-
-// Check if the character at the specified position is blank (space or tab).
-func is_blank(b []byte, i int) bool {
-	//return is_space(b, i) || is_tab(b, i)
-	return b[i] == ' ' || b[i] == '\t'
-}
-
-// Check if the character at the specified position is a line break.
-func is_break(b []byte, i int) bool {
-	return (b[i] == '\r' || // CR (#xD)
-		b[i] == '\n' || // LF (#xA)
-		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
-		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
-		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
-}
-
-func is_crlf(b []byte, i int) bool {
-	return b[i] == '\r' && b[i+1] == '\n'
-}
-
-// Check if the character is a line break or NUL.
-func is_breakz(b []byte, i int) bool {
-	//return is_break(b, i) || is_z(b, i)
-	return (
-	// is_break:
-	b[i] == '\r' || // CR (#xD)
-		b[i] == '\n' || // LF (#xA)
-		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
-		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
-		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
-		// is_z:
-		b[i] == 0)
-}
-
-// Check if the character is a line break, space, or NUL.
-func is_spacez(b []byte, i int) bool {
-	//return is_space(b, i) || is_breakz(b, i)
-	return (
-	// is_space:
-	b[i] == ' ' ||
-		// is_breakz:
-		b[i] == '\r' || // CR (#xD)
-		b[i] == '\n' || // LF (#xA)
-		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
-		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
-		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
-		b[i] == 0)
-}
-
-// Check if the character is a line break, space, tab, or NUL.
-func is_blankz(b []byte, i int) bool {
-	//return is_blank(b, i) || is_breakz(b, i)
-	return (
-	// is_blank:
-	b[i] == ' ' || b[i] == '\t' ||
-		// is_breakz:
-		b[i] == '\r' || // CR (#xD)
-		b[i] == '\n' || // LF (#xA)
-		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
-		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
-		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
-		b[i] == 0)
-}
-
-// Determine the width of the character.
-func width(b byte) int {
-	// Don't replace these by a switch without first
-	// confirming that it is being inlined.
-	if b&0x80 == 0x00 {
-		return 1
-	}
-	if b&0xE0 == 0xC0 {
-		return 2
-	}
-	if b&0xF0 == 0xE0 {
-		return 3
-	}
-	if b&0xF8 == 0xF0 {
-		return 4
-	}
-	return 0
-
-}
tools/review-tool/vendor/modules.txt
@@ -1,3 +0,0 @@
-# gopkg.in/yaml.v3 v3.0.1
-## explicit
-gopkg.in/yaml.v3
tools/review-tool/.gitignore
@@ -1,4 +0,0 @@
-# Binaries
-/review-tool
-/review-tool-debug
-*.exe
tools/review-tool/default.nix
@@ -1,38 +0,0 @@
-{
-  buildGoModule,
-  lib,
-  makeWrapper,
-  gitMinimal,
-  gh,
-}:
-
-buildGoModule {
-  pname = "review-tool";
-  version = "0.3.0";
-  src = ./.;
-
-  vendorHash = null;
-
-  nativeBuildInputs = [ makeWrapper ];
-
-  subPackages = [ "cmd/review-tool" ];
-
-  # Note: jira is NOT bundled here. The tool expects the host's `jira`
-  # wrapper (which injects JIRA_API_TOKEN via passage) to be in PATH.
-  postInstall = ''
-    wrapProgram $out/bin/review-tool \
-      --prefix PATH : ${
-        lib.makeBinPath [
-          gitMinimal
-          gh
-        ]
-      }
-  '';
-
-  meta = {
-    description = "Generate activity review reports from GitHub, Jira, org-mode, and Claude sessions";
-    license = lib.licenses.mit;
-    platforms = lib.platforms.unix;
-    mainProgram = "review-tool";
-  };
-}
tools/review-tool/go.mod
@@ -1,5 +0,0 @@
-module github.com/vdemeester/home/tools/review-tool
-
-go 1.24
-
-require gopkg.in/yaml.v3 v3.0.1
tools/review-tool/go.sum
@@ -1,4 +0,0 @@
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=