<commit_before>package main

import (
	"sync"
	"time"

	"github.com/timeglass/snow/monitor"
)

type Timer struct {
	mbu     time.Duration
	timeout time.Duration
	time    time.Duration
	ticking bool
	read    chan chan time.Duration
	inc     chan chan time.Duration
	reset   chan struct{}

	Wakeup <-chan monitor.DirEvent
	*sync.Mutex
}

func NewTimer(mbu time.Duration, to time.Duration) *Timer {
	t := &Timer{
		mbu:     mbu,
		timeout: to,

		read:  make(chan chan time.Duration),
		inc:   make(chan chan time.Duration),
		reset: make(chan struct{}),

		Wakeup: make(chan monitor.DirEvent),
		Mutex:  &sync.Mutex{},
	}

	//handle read& writes
	go func() {
		for {
			select {
			case r := <-t.read:
				r <- t.time
			case i := <-t.inc:
				t.time += <-i
			case <-t.reset:
				t.time = 0
			}
		}
	}()

	//handle timeout and wakeup
	go func() {
		for {
			select {
			case <-time.After(t.timeout):
				t.Stop()
			case <-t.Wakeup:
				t.Start()
			}
		}
	}()

	return t
}

func (t *Timer) Time() time.Duration {
	r := make(chan time.Duration)
	t.read <- r
	return <-r
}

func (t *Timer) Reset() {
	t.reset <- struct{}{}
}

func (t *Timer) Stop() {
	t.Lock()
	defer t.Unlock()
	t.ticking = false
}

func (t *Timer) Start() {
	t.Lock()
	defer t.Unlock()
	if t.ticking {
		return
	}

	t.ticking = true
	go func() {
		for {

			//increment with mbu
			i := make(chan time.Duration)
			t.inc <- i
			i <- t.mbu

			//wait for next mbu to arrive
			<-time.After(t.mbu)

			//previous tick was the last mbu
			t.Lock()
			defer t.Unlock()
			if !t.ticking {
				return
			}
<commit_msg>fixed regression for 0.5.2 [spent 1m10s]<commit_after>package main

import (
	"sync"
	"time"

	"github.com/timeglass/snow/monitor"
)

type Timer struct {
	mbu     time.Duration
	timeout time.Duration
	time    time.Duration
	ticking bool
	read    chan chan time.Duration
	inc     chan chan time.Duration
	reset   chan struct{}

	Wakeup <-chan monitor.DirEvent
	*sync.Mutex
}

func NewTimer(mbu time.Duration, to time.Duration) *Timer {
	t := &Timer{
		mbu:     mbu,
		timeout: to,

		read:  make(chan chan time.Duration),
		inc:   make(chan chan time.Duration),
		reset: make(chan struct{}),

		Wakeup: make(chan monitor.DirEvent),
		Mutex:  &sync.Mutex{},
	}

	//handle read& writes
	go func() {
		for {
			select {
			case r := <-t.read:
				r <- t.time
			case i := <-t.inc:
				t.time += <-i
			case <-t.reset:
				t.time = 0
			}
		}
	}()

	//handle timeout and wakeup
	go func() {
		for {
			select {
			case <-time.After(t.timeout):
				t.Stop()
			case <-t.Wakeup:
				t.Start()
			}
		}
	}()

	return t
}

func (t *Timer) Time() time.Duration {
	r := make(chan time.Duration)
	t.read <- r
	return <-r
}

func (t *Timer) Reset() {
	t.reset <- struct{}{}
}

func (t *Timer) Stop() {
	t.Lock()
	defer t.Unlock()
	t.ticking = false
}

func (t *Timer) Start() {
	t.Lock()
	defer t.Unlock()
	if t.ticking {
		return
	}

	t.ticking = true
	go func() {
		for {

			//increment with mbu
			i := make(chan time.Duration)
			t.inc <- i
			i <- t.mbu

			//wait for next mbu to arrive
			<-time.After(t.mbu)

			//previous tick was the last mbu
			if !t.ticking {
				return
			}
{'fraction_non_alphanumeric': 0.15272496831432192, 'fraction_numerical': 0.0025348542458808617, 'mean_word_length': 2.3656716417910446, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 3, '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': '2932637', 'n_tokens_mistral': 1453, 'n_tokens_neox': 1248, 'n_words': 338}