<commit_before>package chromedp

import (
	"context"
	"errors"
	"sync"

	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/page"
)

// Navigate navigates the current frame.
func Navigate(urlstr string) Action {
	return ActionFunc(func(ctx context.Context) error {
		frameID, _, _, err := page.Navigate(urlstr).Do(ctx)
		if err != nil {
			return err
		}
		waitLoaded(ctx, frameID)
		return nil
	})
}

func waitLoaded(ctx context.Context, frameID cdp.FrameID) {
	ctx, cancel := context.WithCancel(ctx)
	var wg sync.WaitGroup
	wg.Add(1)
	ListenTarget(ctx, func(ev interface{}) {
		evs, ok := ev.(*page.EventFrameStoppedLoading)
		if ok && evs.FrameID == frameID {
			cancel()
			wg.Done()
		}
	})
	wg.Wait()
}

// NavigationEntries is an action to retrieve the page's navigation history
// entries.
func NavigationEntries(currentIndex *int64, entries *[]*page.NavigationEntry) Action {
	if currentIndex == nil || entries == nil {
		panic("currentIndex and entries cannot be nil")
	}

	return ActionFunc(func(ctx context.Context) error {
		var err error
		*currentIndex, *entries, err = page.GetNavigationHistory().Do(ctx)
		return err
	})
}

// NavigateToHistoryEntry is an action to navigate to the specified navigation
// entry.
func NavigateToHistoryEntry(entryID int64) Action {
	return ActionFunc(func(ctx context.Context) error {
		frameID := FromContext(ctx).Target.cur.ID
		if err := page.NavigateToHistoryEntry(entryID).Do(ctx); err != nil {
			return err
		}
		waitLoaded(ctx, frameID)
		return nil
	})
}

// NavigateBack navigates the current frame backwards in its history.
func NavigateBack() Action {
	return ActionFunc(func(ctx context.Context) error {
		cur, entries, err := page.GetNavigationHistory().Do(ctx)
		if err != nil {
			return err
		}

		if cur <= 0 || cur > int64(len(entries)-1) {
			return errors.New("invalid navigation entry")
		}

		frameID := FromContext(ctx).Target.cur.ID
		entryID := entries[cur-1].ID
		if err := page.NavigateToHistoryEntry(entryID).Do(ctx); err != nil {
			return err
		}
		waitLoaded(ctx, frameID)
		return nil
	})
}

// NavigateForward navigates the current frame forwards in its history.
func NavigateForward() Action {
	return ActionFunc(func(ctx context.Context) error {
		cur, entries, err := page.GetNavigationHistory().Do(ctx)
		if err != nil {
			return err
		}

		if cur < 0 || cur >= int64(len(entries)-1) {
			return errors.New("invalid navigation entry")
		}

		frameID := FromContext(ctx).Target.cur.ID
		entryID := entries[cur+1].ID
		if err := page.NavigateToHistoryEntry(entryID).Do(ctx); err != nil {
			return err
		}
		waitLoaded(ctx, frameID)
		return nil
	})
}

// Reload reloads the current page.
func Reload() Action {
	return ActionFunc(func(ctx context.Context) error {
		frameID := FromContext(ctx).Target.cur.ID
		if err := page.Reload().Do(ctx); err != nil {
			return err
		}
		waitLoaded(ctx, frameID)
		return nil
	})
}

// Stop stops all navigation and pending resource retrieval.
func Stop() Action {
	return page.StopLoading()
}

// CaptureScreenshot captures takes a screenshot of the current viewport.
//
// Note: this an alias for page.CaptureScreenshot.
func CaptureScreenshot(res *[]byte) Action {<commit_msg>set up load event listeners before running cmds<commit_after>package chromedp

import (
	"context"
	"errors"

	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/page"
)

// Navigate navigates the current frame.
func Navigate(urlstr string) Action {
	return ActionFunc(func(ctx context.Context) error {
		ch := listenLoaded(ctx)
		frameID, _, _, err := page.Navigate(urlstr).Do(ctx)
		if err != nil {
			return err
		}
		ch <- frameID
		<-ch
		return nil
	})
}

// listenLoaded sets up a listener before running an action that will load a
// frame, so that later we can block until said frame has finished loading. A
// channel is used to receive the frame ID to wait for and to block, since
// page.Navigate returns the ID, but the listener must be set up before.
func listenLoaded(ctx context.Context) chan cdp.FrameID {
	ch := make(chan cdp.FrameID)
	ctx, cancel := context.WithCancel(ctx)
	var frameID cdp.FrameID
	ListenTarget(ctx, func(ev interface{}) {
		evs, ok := ev.(*page.EventFrameStoppedLoading)
		if !ok {
			return
		}
		if frameID == "" {
			frameID = <-ch
		}
		if evs.FrameID == frameID {
			cancel()
			close(ch)
		}
	})
	return ch
}

// NavigationEntries is an action to retrieve the page's navigation history
// entries.
func NavigationEntries(currentIndex *int64, entries *[]*page.NavigationEntry) Action {
	if currentIndex == nil || entries == nil {
		panic("currentIndex and entries cannot be nil")
	}

	return ActionFunc(func(ctx context.Context) error {
		var err error
		*currentIndex, *entries, err = page.GetNavigationHistory().Do(ctx)
		return err
	})
}

// NavigateToHistoryEntry is an action to navigate to the specified navigation
// entry.
func NavigateToHistoryEntry(entryID int64) Action {
	return ActionFunc(func(ctx context.Context) error {
		ch := listenLoaded(ctx)
		frameID := FromContext(ctx).Target.cur.ID
		if err := page.NavigateToHistoryEntry(entryID).Do(ctx); err != nil {
			return err
		}
		ch <- frameID
		<-ch
		return nil
	})
}

// NavigateBack navigates the current frame backwards in its history.
func NavigateBack() Action {
	return ActionFunc(func(ctx context.Context) error {
		cur, entries, err := page.GetNavigationHistory().Do(ctx)
		if err != nil {
			return err
		}

		if cur <= 0 || cur > int64(len(entries)-1) {
			return errors.New("invalid navigation entry")
		}

		ch := listenLoaded(ctx)
		frameID := FromContext(ctx).Target.cur.ID
		entryID := entries[cur-1].ID
		if err := page.NavigateToHistoryEntry(entryID).Do(ctx); err != nil {
			return err
		}
		ch <- frameID
		<-ch
		return nil
	})
}

// NavigateForward navigates the current frame forwards in its history.
func NavigateForward() Action {
	return ActionFunc(func(ctx context.Context) error {
		cur, entries, err := page.GetNavigationHistory().Do(ctx)
		if err != nil {
			return err
		}

		if cur < 0 || cur >= int64(len(entries)-1) {
			return errors.New("invalid navigation entry")
		}

		ch := listenLoaded(ctx)
		frameID := FromContext(ctx).Target.cur.ID
		entryID := entries[cur+1].ID
		if err := page.NavigateToHistoryEntry(entryID).Do(ctx); err != nil {
			return err
		}
		ch <- frameID
		<-ch
		return nil
	})
}

// Reload reloads the current page.
func Reload() Action {
	return ActionFunc(func(ctx context.Context) error {
		ch := listenLoaded(ctx)
		frameID := FromContext(ctx).Target.cur.ID
		if err := page.Reload().Do(ctx); err != nil {
			return err
		}
		ch <- frameID
		<-ch
		return nil
	})
}

// Stop stops all navigation and pending resource retrieval.
func Stop() Action {
	return page.StopLoading()
}

// CaptureScreenshot captures takes a screenshot of the current viewport.
//
// Note: this an alias for page.CaptureScreenshot.
func CaptureScreenshot(res *[]byte) Action {
{'fraction_non_alphanumeric': 0.12162162162162163, 'fraction_numerical': 0.004169062679700977, 'mean_word_length': 3.7946243969676083, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 7, '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': '1278947', 'n_tokens_mistral': 2447, 'n_tokens_neox': 2233, 'n_words': 658}