<commit_before>// Copyright 2017 The go-hep Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package server

import (
	"encoding/json"
	"errors"
	"fmt"
	"image/color"
	"log"
	"math"
	"net/http"
	"path/filepath"
	"reflect"
	"strings"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hbook/rootcnv"
	"go-hep.org/x/hep/hbook/yodacnv"
	"go-hep.org/x/hep/hplot"
	"go-hep.org/x/hep/rootio"
)

var errNotExist = errors.New("server: object does not exist")

func walk(f rootio.Directory, path []string) (rootio.Object, error) {
	o, ok := f.Get(path[0])
	if !ok {
		return nil, errNotExist
	}
	if dir, ok := o.(rootio.Directory); ok {
		return walk(dir, path[1:])
	}
	return o, nil
}

func (srv *server) plotH1Handle(w http.ResponseWriter, r *http.Request) error {
	url := r.URL.Path[len("/plot-1d/"):]
	toks := strings.Split(url, "/")
	fname := toks[0]

	db, err := srv.db(r)
	if err != nil {
		return err
	}
	db.RLock()
	defer db.RUnlock()

	f := db.get(fname)
	obj, err := walk(f, toks[1:])
	if err != nil {
		return fmt.Errorf("could not find %q in file %q: %v", filepath.Join(toks[1:]...), fname, err)
	}

	robj, ok := obj.(yodacnv.Marshaler)
	if !ok {
		return fmt.Errorf("object %q could not be converted to hbook.H1D", toks[1])
	}
	h1d, err := rootcnv.H1D(robj)
	if err != nil {
		return err
	}

	plot, err := hplot.New()
	if err != nil {
		return err
	}
	plot.Title.Text = obj.(rootio.Named).Title()

	h, err := hplot.NewH1D(h1d)
	if err != nil {
		return err
	}
	h.Infos.Style = hplot.HInfoSummary
	h.Color = color.RGBA{255, 0, 0, 255}

	plot.Add(h, hplot.NewGrid())

	svg, err := renderSVG(plot)
	if err != nil {
		return err
	}

	return json.NewEncoder(w).Encode(string(svg))
}

func (srv *server) plotH2Handle(w http.ResponseWriter, r *http.Request) error {
	log.Printf(">>> request: %q\n", r.URL.Path)
	return json.NewEncoder(w).Encode(map[string]string{
		"url": r.URL.Path,
	})
}

func (srv *server) plotBranchHandle(w http.ResponseWriter, r *http.Request) error {
	url := r.URL.Path[len("/plot-branch/"):]
	toks := strings.Split(url, "/")
	fname := toks[0]

	db, err := srv.db(r)
	if err != nil {
		return err
	}
	db.RLock()
	defer db.RUnlock()

	f := db.get(fname)
	obj, err := walk(f, toks[1:])
	if err != nil {
		return fmt.Errorf("could not find %q in file %q: %v", filepath.Join(toks[1:]...), fname, err)
	}

	tree := obj.(rootio.Tree)

	bname := toks[len(toks)-1]
	b := tree.Branch(bname) // FIXME(sbinet): handle sub-branches
	if b == nil {
		return fmt.Errorf("could not find branch %q in tree %q of file %q", bname, tree.Name(), fname)
	}

	leaves := b.Leaves()
	leaf := leaves[0]
	tname := leaf.TypeName()
	switch {
	case leaf.LeafCount() != nil:
		tname = "[]" + tname
	case leaf.Len() > 1:
		tname = fmt.Sprintf("[%d]%s", leaf.Len(), tname)
	}

	sc, err := rootio.NewScannerVars(tree, rootio.ScanVar{Name: leaf.Name()})
	if err != nil {
		return fmt.Errorf("error creating scanner for branch %q in tree %q of file %q: %v", bname, tree.Name(), fname, err)
	}
	defer sc.Close()

	fv, err := newFloats(leaf)
	if err != nil {
		log.Printf("error creating float-val: %v\n", err)
		return err
	}

	min := +math.MaxFloat64
	max := -math.MaxFloat64
	vals := make([]float64, 0, int(tree.Entries()))
	for sc.Next() {
		err = sc.Scan(fv.ptr)
		if err != nil {
			log.Printf("error scan: %v\n", err)
			return err
		}
		for _, v := range fv.vals() {
			max = math.Max(max, v)
			min = math.Min(min, v)
			vals = append(vals, v)
		}
	}

	err = sc.Err()
	if err != nil {
		log.Printf("error finding min/max: %v\n", err)<commit_msg>rootio/cmd/root-srv/server: make sure file is at 0 before scanning<commit_after>// Copyright 2017 The go-hep Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package server

import (
	"encoding/json"
	"errors"
	"fmt"
	"image/color"
	"log"
	"math"
	"net/http"
	"path/filepath"
	"reflect"
	"strings"

	"go-hep.org/x/hep/hbook"
	"go-hep.org/x/hep/hbook/rootcnv"
	"go-hep.org/x/hep/hbook/yodacnv"
	"go-hep.org/x/hep/hplot"
	"go-hep.org/x/hep/rootio"
)

var errNotExist = errors.New("server: object does not exist")

func walk(f rootio.Directory, path []string) (rootio.Object, error) {
	o, ok := f.Get(path[0])
	if !ok {
		return nil, errNotExist
	}
	if dir, ok := o.(rootio.Directory); ok {
		return walk(dir, path[1:])
	}
	return o, nil
}

func (srv *server) plotH1Handle(w http.ResponseWriter, r *http.Request) error {
	url := r.URL.Path[len("/plot-1d/"):]
	toks := strings.Split(url, "/")
	fname := toks[0]

	db, err := srv.db(r)
	if err != nil {
		return err
	}
	db.RLock()
	defer db.RUnlock()

	f := db.get(fname)
	obj, err := walk(f, toks[1:])
	if err != nil {
		return fmt.Errorf("could not find %q in file %q: %v", filepath.Join(toks[1:]...), fname, err)
	}

	robj, ok := obj.(yodacnv.Marshaler)
	if !ok {
		return fmt.Errorf("object %q could not be converted to hbook.H1D", toks[1])
	}
	h1d, err := rootcnv.H1D(robj)
	if err != nil {
		return err
	}

	plot, err := hplot.New()
	if err != nil {
		return err
	}
	plot.Title.Text = obj.(rootio.Named).Title()

	h, err := hplot.NewH1D(h1d)
	if err != nil {
		return err
	}
	h.Infos.Style = hplot.HInfoSummary
	h.Color = color.RGBA{255, 0, 0, 255}

	plot.Add(h, hplot.NewGrid())

	svg, err := renderSVG(plot)
	if err != nil {
		return err
	}

	return json.NewEncoder(w).Encode(string(svg))
}

func (srv *server) plotH2Handle(w http.ResponseWriter, r *http.Request) error {
	log.Printf(">>> request: %q\n", r.URL.Path)
	return json.NewEncoder(w).Encode(map[string]string{
		"url": r.URL.Path,
	})
}

func (srv *server) plotBranchHandle(w http.ResponseWriter, r *http.Request) error {
	url := r.URL.Path[len("/plot-branch/"):]
	toks := strings.Split(url, "/")
	fname := toks[0]

	db, err := srv.db(r)
	if err != nil {
		return err
	}
	db.RLock()
	defer db.RUnlock()

	f := db.get(fname)
	obj, err := walk(f, toks[1:])
	if err != nil {
		return fmt.Errorf("could not find %q in file %q: %v", filepath.Join(toks[1:]...), fname, err)
	}

	tree := obj.(rootio.Tree)

	bname := toks[len(toks)-1]
	b := tree.Branch(bname) // FIXME(sbinet): handle sub-branches
	if b == nil {
		return fmt.Errorf("could not find branch %q in tree %q of file %q", bname, tree.Name(), fname)
	}

	leaves := b.Leaves()
	leaf := leaves[0]
	tname := leaf.TypeName()
	switch {
	case leaf.LeafCount() != nil:
		tname = "[]" + tname
	case leaf.Len() > 1:
		tname = fmt.Sprintf("[%d]%s", leaf.Len(), tname)
	}

	_, err = f.Seek(0, 0) // FIXME(sbinet): factor this into rootio.Scanner
	if err != nil {
		return fmt.Errorf("error seeking to beginning of file: %v", err)
	}

	sc, err := rootio.NewScannerVars(tree, rootio.ScanVar{Name: leaf.Name()})
	if err != nil {
		return fmt.Errorf("error creating scanner for branch %q in tree %q of file %q: %v", bname, tree.Name(), fname, err)
	}
	defer sc.Close()

	fv, err := newFloats(leaf)
	if err != nil {
		log.Printf("error creating float-val: %v\n", err)
		return err
	}

	min := +math.MaxFloat64
	max := -math.MaxFloat64
	vals := make([]float64, 0, int(tree.Entries()))
	for sc.Next() {
		err = sc.Scan(fv.ptr)
		if err != nil {
			log.Printf("error scan: %v\n", err)
			return err
		}
		for _, v := range fv.vals() {
			max = math.Max(max, v)
			min = math.Min(min, v)
			vals = append(vals, v)
		}
	}

	err = sc.Err()
	if err != nil {
		log.Printf("error finding min/max: %v\n", err)
{'fraction_non_alphanumeric': 0.1854881974248927, 'fraction_numerical': 0.010863733905579398, 'mean_word_length': 3.376173708920188, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7539577', 'n_tokens_mistral': 3266, 'n_tokens_neox': 3115, 'n_words': 783}