How to use conceptFilesChanged method of refactor Package

Best Gauge code snippet using refactor.conceptFilesChanged

refactor.go

Source:refactor.go Github

copy

Full Screen

...51}52func (refactoringResult *refactoringResult) String() string {53	result := fmt.Sprintf("Refactoring result from gauge:\n")54	result += fmt.Sprintf("Specs changed        : %s\n", refactoringResult.specFilesChanged())55	result += fmt.Sprintf("Concepts changed     : %s\n", refactoringResult.conceptFilesChanged())56	result += fmt.Sprintf("Source files changed : %s\n", refactoringResult.runnerFilesChanged())57	result += fmt.Sprintf("Warnings             : %s\n", refactoringResult.Warnings)58	return result59}60func (refactoringResult *refactoringResult) appendWarnings(warnings []*parser.Warning) {61	if refactoringResult.Warnings == nil {62		refactoringResult.Warnings = make([]string, 0)63	}64	for _, warning := range warnings {65		refactoringResult.Warnings = append(refactoringResult.Warnings, warning.Message)66	}67}68func (refactoringResult *refactoringResult) AllFilesChanged() []string {69	filesChanged := make([]string, 0)70	filesChanged = append(filesChanged, refactoringResult.specFilesChanged()...)71	filesChanged = append(filesChanged, refactoringResult.conceptFilesChanged()...)72	filesChanged = append(filesChanged, refactoringResult.runnerFilesChanged()...)73	return filesChanged74}75func (refactoringResult *refactoringResult) conceptFilesChanged() []string {76	filesChanged := make([]string, 0)77	for _, fileChange := range refactoringResult.ConceptsChanged {78		filesChanged = append(filesChanged, fileChange.FileName)79	}80	return filesChanged81}82func (refactoringResult *refactoringResult) specFilesChanged() []string {83	filesChanged := make([]string, 0)84	for _, filesChange := range refactoringResult.SpecsChanged {85		filesChanged = append(filesChanged, filesChange.FileName)86	}87	return filesChanged88}89func (refactoringResult *refactoringResult) runnerFilesChanged() []string {90	filesChanged := make([]string, 0)91	for _, fileChange := range refactoringResult.RunnerFilesChanged {92		filesChanged = append(filesChanged, fileChange.FileName)93	}94	return filesChanged95}96// PerformRephraseRefactoring given an old step and new step refactors specs and concepts in memory and if its a concept writes to file97// else invokes runner to get the step name and refactors the step and sends it to runner to refactor implementation.98func PerformRephraseRefactoring(oldStep, newStep string, startChan *runner.StartChannels, specDirs []string) *refactoringResult {99	defer killRunner(startChan)100	if newStep == oldStep {101		return &refactoringResult{Success: true}102	}103	agent, errs := getRefactorAgent(oldStep, newStep, nil)104	if len(errs) > 0 {105		var messages []string106		for _, err := range errs {107			messages = append(messages, err.Error())108		}109		return rephraseFailure(messages...)110	}111	result, specs, conceptDictionary := parseSpecsAndConcepts(specDirs)112	if !result.Success {113		return result114	}115	refactorResult := agent.performRefactoringOn(specs, conceptDictionary, startChan)116	refactorResult.Warnings = append(refactorResult.Warnings, result.Warnings...)117	return refactorResult118}119// GetRefactoringChanges given an old step and new step gives the list of steps that need to be changed to perform refactoring.120// It also provides the changes to be made on the implementation files.121func GetRefactoringChanges(oldStep, newStep string, runner runner.Runner, specDirs []string) *refactoringResult {122	if newStep == oldStep {123		return &refactoringResult{Success: true}124	}125	agent, errs := getRefactorAgent(oldStep, newStep, runner)126	if len(errs) > 0 {127		var messages []string128		for _, err := range errs {129			messages = append(messages, err.Error())130		}131		return rephraseFailure(messages...)132	}133	result, specs, conceptDictionary := parseSpecsAndConcepts(specDirs)134	if !result.Success {135		return result136	}137	refactorResult := agent.getRefactoringChangesFor(specs, conceptDictionary)138	refactorResult.Warnings = append(refactorResult.Warnings, result.Warnings...)139	return refactorResult140}141func parseSpecsAndConcepts(specDirs []string) (*refactoringResult, []*gauge.Specification, *gauge.ConceptDictionary) {142	result := &refactoringResult{Success: true, Errors: make([]string, 0), Warnings: make([]string, 0)}143	var specs []*gauge.Specification144	var specParseResults []*parser.ParseResult145	for _, dir := range specDirs {146		specFiles := util.GetSpecFiles([]string{filepath.Join(config.ProjectRoot, dir)})147		specSlice, specParseResultsSlice := parser.ParseSpecFiles(specFiles, &gauge.ConceptDictionary{}, gauge.NewBuildErrors())148		specs = append(specs, specSlice...)149		specParseResults = append(specParseResults, specParseResultsSlice...)150	}151	addErrorsAndWarningsToRefactoringResult(result, specParseResults...)152	if !result.Success {153		return result, nil, nil154	}155	conceptDictionary, parseResult, err := parser.CreateConceptsDictionary()156	if err != nil {157		return rephraseFailure(err.Error()), nil, nil158	}159	addErrorsAndWarningsToRefactoringResult(result, parseResult)160	return result, specs, conceptDictionary161}162func killRunner(startChan *runner.StartChannels) {163	startChan.KillChan <- true164}165func rephraseFailure(errors ...string) *refactoringResult {166	return &refactoringResult{Success: false, Errors: errors}167}168func addErrorsAndWarningsToRefactoringResult(refactorResult *refactoringResult, parseResults ...*parser.ParseResult) {169	for _, parseResult := range parseResults {170		if !parseResult.Ok {171			refactorResult.Success = false172			for _, err := range parseResult.Errors() {173				refactorResult.Errors = append(refactorResult.Errors, err)174			}175		}176		refactorResult.appendWarnings(parseResult.Warnings)177	}178}179func (agent *rephraseRefactorer) performRefactoringOn(specs []*gauge.Specification, conceptDictionary *gauge.ConceptDictionary, startChan *runner.StartChannels) *refactoringResult {180	specsRefactored, conceptFilesRefactored := agent.rephraseInSpecsAndConcepts(&specs, conceptDictionary)181	var runner runner.Runner182	select {183	case runner = <-startChan.RunnerChan:184	case err := <-startChan.ErrorChan:185		logger.Debugf(true, "Cannot perform refactoring: Unable to connect to runner."+err.Error())186		return &refactoringResult{Success: false, Errors: make([]string, 0), Warnings: make([]string, 0)}187	}188	agent.runner = runner189	result := agent.refactorStepImplementations(true)190	if !result.Success {191		return result192	}193	result.SpecsChanged, result.ConceptsChanged = getFileChanges(specs, conceptDictionary, specsRefactored, conceptFilesRefactored)194	writeFileChangesToDisk(result)195	return result196}197func writeFileChangesToDisk(result *refactoringResult) {198	for _, fileChange := range result.SpecsChanged {199		util.SaveFile(fileChange.FileName, fileChange.FileContent, true)200	}201	for _, fileChange := range result.ConceptsChanged {202		util.SaveFile(fileChange.FileName, fileChange.FileContent, true)203	}204}205func (agent *rephraseRefactorer) getRefactoringChangesFor(specs []*gauge.Specification, conceptDictionary *gauge.ConceptDictionary) *refactoringResult {206	specsRefactored, conceptFilesRefactored := agent.rephraseInSpecsAndConcepts(&specs, conceptDictionary)207	result := agent.refactorStepImplementations(false)208	if !result.Success {209		return result210	}211	result.SpecsChanged, result.ConceptsChanged = getFileChanges(specs, conceptDictionary, specsRefactored, conceptFilesRefactored)212	return result213}214func (agent *rephraseRefactorer) refactorStepImplementations(shouldSaveChanges bool) *refactoringResult {215	result := &refactoringResult{Success: false, Errors: make([]string, 0), Warnings: make([]string, 0)}216	if !agent.isConcept {217		stepName, err, warning := agent.getStepNameFromRunner(agent.runner)218		if err != nil {219			result.Errors = append(result.Errors, err.Error())220			return result221		}222		if warning == nil {223			runnerFilesChanged, err := agent.requestRunnerForRefactoring(agent.runner, stepName, shouldSaveChanges)224			if err != nil {225				result.Errors = append(result.Errors, fmt.Sprintf("Cannot perform refactoring: %s", err))226				return result227			}228			result.RunnerFilesChanged = runnerFilesChanged229		} else {230			result.Warnings = append(result.Warnings, warning.Message)231		}232	}233	result.Success = true234	return result235}236func (agent *rephraseRefactorer) rephraseInSpecsAndConcepts(specs *[]*gauge.Specification, conceptDictionary *gauge.ConceptDictionary) (map[*gauge.Specification][]*gauge.StepDiff, map[string][]*gauge.StepDiff) {237	specsRefactored := make(map[*gauge.Specification][]*gauge.StepDiff, 0)238	conceptsRefactored := make(map[string][]*gauge.StepDiff, 0)239	orderMap := agent.createOrderOfArgs()240	for _, spec := range *specs {241		diffs, isRefactored := spec.RenameSteps(*agent.oldStep, *agent.newStep, orderMap)242		if isRefactored {243			specsRefactored[spec] = diffs244		}245	}246	isConcept := false247	for _, concept := range conceptDictionary.ConceptsMap {248		isRefactored := false249		for _, item := range concept.ConceptStep.Items {250			if item.Kind() == gauge.StepKind {251				diff, isRefactored := item.(*gauge.Step).Rename(*agent.oldStep, *agent.newStep, isRefactored, orderMap, &isConcept)252				if isRefactored {253					conceptsRefactored[concept.FileName] = append(conceptsRefactored[concept.FileName], diff)254				}255			}256		}257	}258	agent.isConcept = isConcept259	return specsRefactored, conceptsRefactored260}261func (agent *rephraseRefactorer) createOrderOfArgs() map[int]int {262	orderMap := make(map[int]int, len(agent.newStep.Args))263	for i, arg := range agent.newStep.Args {264		orderMap[i] = SliceIndex(len(agent.oldStep.Args), func(i int) bool { return agent.oldStep.Args[i].String() == arg.String() })265	}266	return orderMap267}268// SliceIndex gives the index of the args.269func SliceIndex(limit int, predicate func(i int) bool) int {270	for i := 0; i < limit; i++ {271		if predicate(i) {272			return i273		}274	}275	return -1276}277func getRefactorAgent(oldStepText, newStepText string, runner runner.Runner) (*rephraseRefactorer, []parser.ParseError) {278	specParser := new(parser.SpecParser)279	stepTokens, errs := specParser.GenerateTokens("* "+oldStepText+"\n"+"*"+newStepText, "")280	if len(errs) > 0 {281		return nil, errs282	}283	steps := make([]*gauge.Step, 0)284	for _, stepToken := range stepTokens {285		step, parseRes := parser.CreateStepUsingLookup(stepToken, nil, "")286		if parseRes != nil && len(parseRes.ParseErrors) > 0 {287			return nil, parseRes.ParseErrors288		}289		steps = append(steps, step)290	}291	return &rephraseRefactorer{oldStep: steps[0], newStep: steps[1], runner: runner}, []parser.ParseError{}292}293func (agent *rephraseRefactorer) requestRunnerForRefactoring(testRunner runner.Runner, stepName string, shouldSaveChanges bool) ([]*gauge_messages.FileChanges, error) {294	refactorRequest, err := agent.createRefactorRequest(testRunner, stepName, shouldSaveChanges)295	if err != nil {296		return nil, err297	}298	refactorResponse := agent.sendRefactorRequest(testRunner, refactorRequest)299	var runnerError error300	if !refactorResponse.GetSuccess() {301		logger.Errorf(false, "Refactoring error response from runner: %v", refactorResponse.GetError())302		runnerError = errors.New(refactorResponse.GetError())303	}304	if len(refactorResponse.GetFileChanges()) == 0 {305		for _, file := range refactorResponse.GetFilesChanged() {306			refactorResponse.FileChanges = append(refactorResponse.FileChanges, &gauge_messages.FileChanges{FileName: file})307		}308	}309	return refactorResponse.GetFileChanges(), runnerError310}311func (agent *rephraseRefactorer) sendRefactorRequest(testRunner runner.Runner, refactorRequest *gauge_messages.Message) *gauge_messages.RefactorResponse {312	response, err := testRunner.ExecuteMessageWithTimeout(refactorRequest)313	if err != nil {314		return &gauge_messages.RefactorResponse{Success: false, Error: err.Error()}315	}316	return response.GetRefactorResponse()317}318//Todo: Check for inline tables319func (agent *rephraseRefactorer) createRefactorRequest(runner runner.Runner, stepName string, shouldSaveChanges bool) (*gauge_messages.Message, error) {320	oldStepValue, err := agent.getStepValueFor(agent.oldStep, stepName)321	if err != nil {322		return nil, err323	}324	orderMap := agent.createOrderOfArgs()325	newStepName := agent.generateNewStepName(oldStepValue.Args, orderMap)326	newStepValue, err := parser.ExtractStepValueAndParams(newStepName, false)327	if err != nil {328		return nil, err329	}330	oldProtoStepValue := gauge.ConvertToProtoStepValue(oldStepValue)331	newProtoStepValue := gauge.ConvertToProtoStepValue(newStepValue)332	return &gauge_messages.Message{MessageType: gauge_messages.Message_RefactorRequest,333		RefactorRequest: &gauge_messages.RefactorRequest{334			OldStepValue:   oldProtoStepValue,335			NewStepValue:   newProtoStepValue,336			ParamPositions: agent.createParameterPositions(orderMap),337			SaveChanges:    shouldSaveChanges,338		},339	}, nil340}341func (agent *rephraseRefactorer) generateNewStepName(args []string, orderMap map[int]int) string {342	agent.newStep.PopulateFragments()343	paramIndex := 0344	for _, fragment := range agent.newStep.Fragments {345		if fragment.GetFragmentType() == gauge_messages.Fragment_Parameter {346			if orderMap[paramIndex] != -1 {347				fragment.GetParameter().Value = args[orderMap[paramIndex]]348			}349			paramIndex++350		}351	}352	return parser.ConvertToStepText(agent.newStep.Fragments)353}354func (agent *rephraseRefactorer) getStepNameFromRunner(runner runner.Runner) (string, error, *parser.Warning) {355	stepNameMessage := &gauge_messages.Message{MessageType: gauge_messages.Message_StepNameRequest, StepNameRequest: &gauge_messages.StepNameRequest{StepValue: agent.oldStep.Value}}356	responseMessage, err := runner.ExecuteMessageWithTimeout(stepNameMessage)357	if err != nil {358		return "", err, nil359	}360	if !(responseMessage.GetStepNameResponse().GetIsStepPresent()) {361		return "", nil, &parser.Warning{Message: fmt.Sprintf("Step implementation not found: %s", agent.oldStep.LineText)}362	}363	if responseMessage.GetStepNameResponse().GetHasAlias() {364		return "", fmt.Errorf("steps with aliases : '%s' cannot be refactored", strings.Join(responseMessage.GetStepNameResponse().GetStepName(), "', '")), nil365	}366	return responseMessage.GetStepNameResponse().GetStepName()[0], nil, nil367}368func (agent *rephraseRefactorer) createParameterPositions(orderMap map[int]int) []*gauge_messages.ParameterPosition {369	paramPositions := make([]*gauge_messages.ParameterPosition, 0)370	for k, v := range orderMap {371		paramPositions = append(paramPositions, &gauge_messages.ParameterPosition{NewPosition: int32(k), OldPosition: int32(v)})372	}373	return paramPositions374}375func (agent *rephraseRefactorer) getStepValueFor(step *gauge.Step, stepName string) (*gauge.StepValue, error) {376	return parser.ExtractStepValueAndParams(stepName, false)377}378func createDiffs(diffs []*gauge.StepDiff) []*gauge_messages.TextDiff {379	textDiffs := []*gauge_messages.TextDiff{}380	for _, diff := range diffs {381		newtext := strings.TrimSpace(formatter.FormatStep(diff.NewStep))382		if diff.IsConcept && !diff.OldStep.InConcept() {383			newtext = strings.Replace(newtext, "*", "#", -1)384		}385		oldFragments := util.GetLinesFromText(strings.TrimSpace(formatter.FormatStep(&diff.OldStep)))386		d := &gauge_messages.TextDiff{387			Span: &gauge_messages.Span{388				Start:     int64(diff.OldStep.LineNo),389				StartChar: 0,390				End:       int64(diff.OldStep.LineNo + len(oldFragments) - 1),391				EndChar:   int64(len(oldFragments[len(oldFragments)-1])),392			},393			Content: newtext,394		}395		textDiffs = append(textDiffs, d)396	}397	return textDiffs398}399func getFileChanges(specs []*gauge.Specification, conceptDictionary *gauge.ConceptDictionary, specsRefactored map[*gauge.Specification][]*gauge.StepDiff, conceptsRefactored map[string][]*gauge.StepDiff) ([]*gauge_messages.FileChanges, []*gauge_messages.FileChanges) {400	specFiles := []*gauge_messages.FileChanges{}401	conceptFiles := []*gauge_messages.FileChanges{}402	for _, spec := range specs {403		if stepDiffs, ok := specsRefactored[spec]; ok {404			formatted := formatter.FormatSpecification(spec)405			specFiles = append(specFiles, &gauge_messages.FileChanges{FileName: spec.FileName, FileContent: formatted, Diffs: createDiffs(stepDiffs)})406		}407	}408	conceptMap := formatter.FormatConcepts(conceptDictionary)409	for file, diffs := range conceptsRefactored {410		conceptFiles = append(conceptFiles, &gauge_messages.FileChanges{FileName: file, FileContent: conceptMap[file], Diffs: createDiffs(diffs)})411	}412	return specFiles, conceptFiles413}414func printRefactoringSummary(refactoringResult *refactoringResult) {415	exitCode := 0416	if !refactoringResult.Success {417		exitCode = 1418		for _, err := range refactoringResult.Errors {419			logger.Errorf(true, "%s \n", err)420		}421	}422	for _, warning := range refactoringResult.Warnings {423		logger.Warningf(true, "%s \n", warning)424	}425	logger.Infof(true, "%d specifications changed.\n", len(refactoringResult.specFilesChanged()))426	logger.Infof(true, "%d concepts changed.\n", len(refactoringResult.conceptFilesChanged()))427	logger.Infof(true, "%d files in code changed.\n", len(refactoringResult.RunnerFilesChanged))428	os.Exit(exitCode)429}430// RefactorSteps performs rephrase refactoring and prints the refactoring summary which includes errors and warnings generated during refactoring and431// files changed during refactoring : specification files, concept files and the implementation files changed.432func RefactorSteps(oldStep, newStep string, startChan *runner.StartChannels, specDirs []string) {433	refactoringResult := PerformRephraseRefactoring(oldStep, newStep, startChan, specDirs)434	printRefactoringSummary(refactoringResult)435}...

Full Screen

Full Screen

conceptFilesChanged

Using AI Code Generation

copy

Full Screen

1import (2func main() {3    prog := gas.NewProgram()4    r := refactor.NewRefactor(prog)5    conf := loader.Config{}6    conf.CreateFromFilenames("main", "test.go")7    lprog, err := conf.Load()8    if err != nil {9        log.Fatal(err)10    }11    packages := ssautil.AllPackages(lprog, 0)12    packages.Build()13    filename := file.Pos().Filename()14    path := os.Getenv("GOPATH") + "/src/" + filename15    changes := r.ConceptFilesChanged(path)16    fmt.Println(changes)17}18import (19func main() {20    prog := gas.NewProgram()21    r := refactor.NewRefactor(prog)22    conf := loader.Config{}23    conf.CreateFromFilenames("main", "test.go")24    lprog, err := conf.Load()25    if err != nil {26        log.Fatal(err)27    }

Full Screen

Full Screen

conceptFilesChanged

Using AI Code Generation

copy

Full Screen

1import (2func main() {3	r.ConceptFilesChanged()4}5import (6func main() {7	r.ConceptFilesChanged()8}9import (10type Refactor struct{}11func (r Refactor) ConceptFilesChanged() {12	fmt.Println("conceptFilesChanged")13}14import (15func TestConceptFilesChanged(t *testing.T) {16	r.ConceptFilesChanged()17}18import (19type Refactor struct{}20func (r Refactor) ConceptFilesChanged() {21	fmt.Println("conceptFilesChanged")22}23import (24func TestConceptFilesChanged(t *testing.T) {25	r.ConceptFilesChanged()26}27import (28type Refactor struct{}29func (r Refactor) ConceptFilesChanged() {30	fmt.Println("conceptFilesChanged")31}32import (33func TestConceptFilesChanged(t *testing.T) {34	r.ConceptFilesChanged()35}36import (37type Refactor struct{}38func (r Refactor) ConceptFilesChanged() {39	fmt.Println("conceptFilesChanged")40}41import (42func TestConceptFilesChanged(t *testing.T) {43	r.ConceptFilesChanged()44}

Full Screen

Full Screen

conceptFilesChanged

Using AI Code Generation

copy

Full Screen

1import (2func main() {3    ref := refactor.NewRefactor()4    files, err := ref.conceptFilesChanged("master", "master")5    if err != nil {6        log.Fatal(err)7    }8    fmt.Println(files)9}

Full Screen

Full Screen

conceptFilesChanged

Using AI Code Generation

copy

Full Screen

1import (2func main() {3	r := autoref.NewRefactor()4	c := autoref.NewRefactorConfig()5	result := autoref.NewRefactorResult()6	r.SetConfig(c)7	r.SetResult(result)8	r.ConceptFilesChanged("github.com/ericaro/autoref")9	fmt.Println(r.Result())10}11{map[github.com/ericaro/autoref/concepts/autoref.go:github.com/ericaro/autoref/autoref.go]map[]map[]}12type RefactorResult struct {13}

Full Screen

Full Screen

conceptFilesChanged

Using AI Code Generation

copy

Full Screen

1import (2func main() {3	fmt.Println("Enter the path of the directory to be refactored")4	reader := bufio.NewReader(os.Stdin)5	input, _ := reader.ReadString('6	input = strings.TrimSuffix(input, "7	fmt.Println("Enter the path of the directory where refactored files are to be stored")8	reader = bufio.NewReader(os.Stdin)9	output, _ := reader.ReadString('10	output = strings.TrimSuffix(output, "11	fmt.Println("Enter the name of the concept file")12	reader = bufio.NewReader(os.Stdin)13	concept, _ := reader.ReadString('14	concept = strings.TrimSuffix(concept, "15	refactor.ConceptFilesChanged(input, output, concept)16}17import (18type Concept struct {19}20type Refactor struct {21}22func (r *Refactor) ConceptFilesChanged(input string, output string, concept string) {23	r.ConceptFiles = make([]string, 0)24	r.ConceptFiles = append(r.ConceptFiles, input)25	r.ConceptFiles = append(r.ConceptFiles, output)26	r.ConceptFiles = append(r.ConceptFiles, concept)27	fmt.Println(r.ConceptFiles)28	r.readConceptFile()29}30func (r *Refactor) readConceptFile() {31	conceptFile, err := os.Open(r.ConceptFiles[2])32	if err != nil {33		fmt.Println(err)34	}35	defer conceptFile.Close()36	scanner := bufio.NewScanner(conceptFile)37	scanner.Split(bufio.ScanLines)38	for scanner.Scan() {39		concept = concept + scanner.Text()40	}41	r.parseConceptFile(concept)42}43func (r *Refactor) parseConceptFile(concept string) {44	err := json.Unmarshal([]byte(concept), &conceptStruct)45	if err != nil {46		fmt.Println(err)47	}48	fmt.Println(conceptStruct.Name)49	fmt.Println(conceptStruct.Concept)50	r.readInputFile(conceptStruct.Name, conceptStruct.Concept

Full Screen

Full Screen

conceptFilesChanged

Using AI Code Generation

copy

Full Screen

1import (2	"golang.org/x/tools/refactor/importgraph"3func main() {4	conf := loader.Config{5	}6	conf.ImportWithTests(".")

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Gauge automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Most used method in

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful