github.com/easysoft/zendata@v0.0.0-20240513203326-705bd5a7fd67/internal/pkg/service/range.go (about)

     1  package service
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"regexp"
     7  	"strconv"
     8  	"strings"
     9  	"unicode"
    10  
    11  	consts "github.com/easysoft/zendata/internal/pkg/const"
    12  	"github.com/easysoft/zendata/internal/pkg/domain"
    13  	"github.com/easysoft/zendata/internal/pkg/helper"
    14  	commonUtils "github.com/easysoft/zendata/pkg/utils/common"
    15  	fileUtils "github.com/easysoft/zendata/pkg/utils/file"
    16  	stringUtils "github.com/easysoft/zendata/pkg/utils/string"
    17  	"github.com/easysoft/zendata/pkg/utils/vari"
    18  )
    19  
    20  type RangeService struct {
    21  	PlaceholderService *PlaceholderService `inject:""`
    22  	ListService        *ListService        `inject:""`
    23  	RandomService      *RandomService      `inject:""`
    24  
    25  	DefService     *DefService     `inject:""`
    26  	PrintService   *PrintService   `inject:""`
    27  	CombineService *CombineService `inject:""`
    28  	OutputService  *OutputService  `inject:""`
    29  	FileService    *FileService    `inject:""`
    30  
    31  	RangeService *RangeService `inject:""`
    32  	MainService  *MainService  `inject:""`
    33  }
    34  
    35  func (s *RangeService) CreateFieldValuesFromRange(field *domain.DefField) {
    36  	rang := field.Range
    37  	rangLiteral := field.RangeLiteral
    38  
    39  	if rangLiteral != "" {
    40  		field.Values = append(field.Values, rangLiteral)
    41  		return
    42  	}
    43  
    44  	// gen empty values
    45  	if rang == "" {
    46  		regx := regexp.MustCompile(`.+\(.*\)`)
    47  		isFunc := regx.MatchString(field.Format)
    48  
    49  		for i := 0; i < vari.GlobalVars.Total; i++ {
    50  			field.Values = append(field.Values, "")
    51  
    52  			if !isFunc { // gen multi records for format function
    53  				break
    54  			}
    55  		}
    56  		return
    57  	}
    58  
    59  	field.IsNumb = true
    60  
    61  	// gen from field's range
    62  	rangeSections := s.ParseRangeProperty(rang) // parse 1
    63  
    64  	index := 0
    65  	for _, rangeSection := range rangeSections {
    66  		if index >= consts.MaxNumb {
    67  			break
    68  		}
    69  		if rangeSection == "" {
    70  			continue
    71  		}
    72  
    73  		descStr, stepStr, count, countTag := s.ParseRangeSection(rangeSection) // parse 2
    74  		if strings.ToLower(stepStr) == "r" {
    75  			(*field).IsRand = true
    76  		}
    77  
    78  		typ, desc := s.ParseRangeSectionDesc(descStr) // parse 3
    79  
    80  		items := make([]interface{}, 0)
    81  		if typ == "interval" {
    82  			items = s.CreateValuesFromInterval(field, desc, stepStr, count, countTag)
    83  
    84  		} else if typ == "literal" {
    85  			items = s.CreateValuesFromLiteral(field, desc, stepStr, count, countTag)
    86  
    87  		} else if typ == "yaml" { // load from a yaml
    88  			items = s.CreateValuesFromYaml(field, desc, stepStr, count, countTag)
    89  			field.ReferToAnotherYaml = true
    90  		}
    91  
    92  		for _, item := range items {
    93  			field.Values = append(field.Values, item)
    94  		}
    95  
    96  		index = index + len(items)
    97  	}
    98  
    99  	if len(field.Values) == 0 {
   100  		field.Values = append(field.Values, "N/A")
   101  	}
   102  }
   103  
   104  func (s *RangeService) CreateValuesFromLiteral(field *domain.DefField, desc string, stepStr string, repeat int, repeatTag string) (items []interface{}) {
   105  	field.IsNumb = false
   106  
   107  	elemArr := s.ParseDesc(desc)
   108  	step, _ := strconv.Atoi(stepStr)
   109  	if step == 0 {
   110  		step = 1
   111  	}
   112  	total := 0
   113  
   114  	if field.Path != "" && stepStr == "r" {
   115  		pth := field.Path
   116  		key := s.GetRandFieldSection(pth)
   117  
   118  		items = append(items, s.PlaceholderService.PlaceholderStr(key))
   119  		mp := s.PlaceholderService.PlaceholderMapForRandValues("list", elemArr, "", "", "", "",
   120  			field.Format, repeat, repeatTag)
   121  
   122  		vari.GlobalVars.RandFieldSectionShortKeysToPathMap[key] = pth
   123  		vari.GlobalVars.RandFieldSectionPathToValuesMap[key] = mp
   124  		return
   125  	}
   126  
   127  	if repeatTag == "" {
   128  		for i := 0; i < len(elemArr); {
   129  			idx := i
   130  			if field.Path == "" && stepStr == "r" {
   131  				idx = commonUtils.RandNum(len(elemArr)) // should set random here too
   132  			}
   133  
   134  			val := elemArr[idx]
   135  			val = strings.Trim(val, "`")
   136  			total = s.ListService.AppendValues(&items, val, repeat, total)
   137  
   138  			if total >= consts.MaxNumb {
   139  				break
   140  			}
   141  			i += step
   142  		}
   143  	} else if repeatTag == "!" {
   144  		isRand := field.Path == "" && stepStr == "r"
   145  		for i := 0; i < repeat; {
   146  			total = s.ListService.AppendArrItems(&items, elemArr, total, isRand)
   147  
   148  			if total >= consts.MaxNumb {
   149  				break
   150  			}
   151  			i += step
   152  		}
   153  	}
   154  
   155  	if field.Path == "" && stepStr == "r" { // for ranges and instances, random
   156  		items = s.RandomService.RandomInterfaces(items)
   157  	}
   158  
   159  	return
   160  }
   161  
   162  func (s *RangeService) CreateValuesFromInterval(field *domain.DefField, desc, stepStr string, repeat int, repeatTag string) (items []interface{}) {
   163  	elemArr := strings.Split(desc, "-")
   164  	startStr := elemArr[0]
   165  	endStr := startStr
   166  	if len(elemArr) > 1 {
   167  		endStr = elemArr[1]
   168  	}
   169  
   170  	dataType, step, precision, rand, _ := s.CheckRangeType(startStr, endStr, stepStr)
   171  	field.Precision = precision
   172  
   173  	// 1. random replacement
   174  	if field.Path != "" && dataType != "string" && rand { // random. for res, field.Path == ""
   175  		pth := field.Path + "->" + desc
   176  		key := s.GetRandFieldSection(pth)
   177  
   178  		val := s.PlaceholderService.PlaceholderStr(key)
   179  		strItems := make([]string, 0)
   180  
   181  		// chang to add only one placeholder item
   182  		items = append(items, val)
   183  		strItems = append(strItems, val)
   184  
   185  		mp := s.PlaceholderService.PlaceholderMapForRandValues(dataType, strItems, startStr, endStr, fmt.Sprintf("%v", step),
   186  			strconv.Itoa(precision), field.Format, repeat, repeatTag)
   187  
   188  		vari.GlobalVars.RandFieldSectionShortKeysToPathMap[key] = pth
   189  		vari.GlobalVars.RandFieldSectionPathToValuesMap[key] = mp
   190  
   191  		return
   192  	}
   193  
   194  	if dataType == "int" {
   195  		startInt, _ := strconv.ParseInt(startStr, 0, 64)
   196  		endInt, _ := strconv.ParseInt(endStr, 0, 64)
   197  
   198  		items = helper.GenerateItems(startInt, endInt, int64(step.(int)), 0, rand, repeat, repeatTag, 0)
   199  
   200  	} else if dataType == "float" {
   201  		startFloat, _ := strconv.ParseFloat(startStr, 64)
   202  		endFloat, _ := strconv.ParseFloat(endStr, 64)
   203  		field.Precision = precision
   204  
   205  		items = helper.GenerateItems(startFloat, endFloat, step.(float64), field.Precision, rand, repeat, repeatTag, 0)
   206  
   207  	} else if dataType == "char" {
   208  		field.IsNumb = false
   209  
   210  		items = helper.GenerateItems(startStr[0], endStr[0], int64(step.(int)), 0, rand, repeat, repeatTag, 0)
   211  
   212  	} else if dataType == "string" {
   213  		field.IsNumb = false
   214  
   215  		if repeat == 0 {
   216  			repeat = 1
   217  		}
   218  		for i := 0; i < repeat; i++ {
   219  			items = append(items, desc)
   220  		}
   221  	}
   222  
   223  	if field.Path == "" && stepStr == "r" { // for ranges and instances, random again
   224  		items = s.RandomService.RandomInterfaces(items)
   225  	}
   226  
   227  	return
   228  }
   229  
   230  func (s *RangeService) CreateValuesFromYaml(field *domain.DefField, yamlFile, stepStr string, repeat int, repeatTag string) (items []interface{}) {
   231  	field.IsNumb = false
   232  
   233  	// keep root def, since vari.ZdDef will be overwrite by refer yaml file
   234  	rootDef := vari.GlobalVars.DefData
   235  	configDir := vari.GlobalVars.ConfigFileDir
   236  	exportFields := vari.GlobalVars.ExportFields
   237  	res := vari.GlobalVars.ResData
   238  
   239  	vari.GlobalVars.ExportFields = make([]string, 0) // set to empty to use all fields
   240  
   241  	configFile := s.FileService.ComputerReferFilePath(yamlFile, field)
   242  
   243  	vari.GlobalVars.ConfigFileDir = fileUtils.GetAbsDir(configFile)
   244  	s.MainService.GenerateDataByFile([]string{configFile})
   245  
   246  	// get the data
   247  	items = s.OutputService.GenText(true)
   248  
   249  	if field.Rand {
   250  		items = s.RandomService.RandomValues(items)
   251  	}
   252  
   253  	if repeat > 0 {
   254  		if repeat > len(items) {
   255  			repeat = len(items)
   256  		}
   257  		items = items[:repeat]
   258  	}
   259  
   260  	// rollback root def when finish to deal with refer yaml file
   261  	vari.GlobalVars.DefData = rootDef
   262  	vari.GlobalVars.ConfigFileDir = configDir
   263  	vari.GlobalVars.ExportFields = exportFields
   264  	vari.GlobalVars.ResData = res
   265  
   266  	return
   267  }
   268  
   269  func (s *RangeService) DealwithFixRange(field *domain.DefField) {
   270  	if s.FixIsARange(field.Prefix) {
   271  		field.PrefixRange = s.CreateAffixValuesFromRange(field.Prefix, field)
   272  	} else {
   273  		var tmp interface{}
   274  		tmp = field.Prefix
   275  		field.PrefixRange = &domain.Range{Values: []interface{}{tmp}}
   276  	}
   277  
   278  	if s.FixIsARange(field.Postfix) {
   279  		field.PostfixRange = s.CreateAffixValuesFromRange(field.Postfix, field)
   280  	} else {
   281  		var tmp interface{}
   282  		tmp = field.Postfix
   283  		field.PostfixRange = &domain.Range{Values: []interface{}{tmp}}
   284  	}
   285  }
   286  
   287  func (s *RangeService) CreateAffixValuesFromRange(strRang string, field *domain.DefField) (rang *domain.Range) {
   288  	rang = &domain.Range{}
   289  
   290  	if strRang == "" {
   291  		return
   292  	}
   293  
   294  	rangeSections := s.ParseRangeProperty(strRang) // parse 1
   295  
   296  	index := 0
   297  	for _, rangeSection := range rangeSections {
   298  		if index >= vari.GlobalVars.Total {
   299  			break
   300  		}
   301  
   302  		if rangeSection == "" {
   303  			continue
   304  		}
   305  
   306  		descStr, stepStr, count, countTag := s.ParseRangeSection(rangeSection) // parse 2
   307  		if strings.ToLower(stepStr) == "r" {
   308  			rang.IsRand = true
   309  		}
   310  
   311  		typ, desc := s.ParseRangeSectionDesc(descStr) // parse 3
   312  
   313  		items := make([]interface{}, 0)
   314  		if typ == "literal" {
   315  			items = s.CreateValuesFromLiteral(field, desc, stepStr, count, countTag)
   316  
   317  		} else if typ == "interval" {
   318  			items = s.CreateValuesFromInterval(field, desc, stepStr, count, countTag)
   319  
   320  		} else if typ == "yaml" { // load from a yaml
   321  			items = s.CreateValuesFromYaml(field, desc, stepStr, count, countTag)
   322  			field.ReferToAnotherYaml = true
   323  
   324  		}
   325  
   326  		rang.Values = append(rang.Values, items...)
   327  		index = index + len(items)
   328  	}
   329  
   330  	if len(rang.Values) == 0 {
   331  		rang.Values = append(rang.Values, "N/A")
   332  	}
   333  
   334  	return
   335  }
   336  
   337  func (s *RangeService) FixIsARange(fix string) bool {
   338  	index := strings.Index(fix, "-")
   339  
   340  	return index > 0 && index < len(fix)-1
   341  }
   342  
   343  func (s *RangeService) ParseRangeProperty(rang string) []string {
   344  	items := make([]string, 0)
   345  
   346  	bracketsOpen := false
   347  	backtickOpen := false
   348  	temp := ""
   349  
   350  	rang = strings.Trim(rang, ",")
   351  	runeArr := []rune(rang)
   352  
   353  	for i := 0; i < len(runeArr); i++ {
   354  		c := runeArr[i]
   355  
   356  		if c == consts.RightBrackets {
   357  			bracketsOpen = false
   358  		} else if c == consts.LeftBrackets {
   359  			bracketsOpen = true
   360  		} else if !backtickOpen && c == consts.Backtick {
   361  			backtickOpen = true
   362  		} else if backtickOpen && c == consts.Backtick {
   363  			backtickOpen = false
   364  		}
   365  
   366  		if i == len(runeArr)-1 {
   367  			temp += fmt.Sprintf("%c", c)
   368  			items = append(items, temp)
   369  		} else if !bracketsOpen && !backtickOpen && c == ',' {
   370  			items = append(items, temp)
   371  			temp = ""
   372  			bracketsOpen = false
   373  			backtickOpen = false
   374  		} else {
   375  			temp += fmt.Sprintf("%c", c)
   376  		}
   377  	}
   378  
   379  	return items
   380  }
   381  
   382  // for Literal only
   383  func (s *RangeService) ParseDesc(desc string) (items []string) {
   384  	desc = strings.TrimSpace(desc)
   385  	desc = strings.Trim(desc, ",")
   386  
   387  	if desc == "" {
   388  		items = append(items, desc)
   389  		return
   390  	}
   391  
   392  	runeArr := []rune(desc)
   393  
   394  	if runeArr[0] == consts.Backtick && runeArr[len(runeArr)-1] == consts.Backtick { // `xxx`
   395  		desc = string(runeArr[1 : len(runeArr)-1])
   396  		items = append(items, desc)
   397  
   398  	} else if runeArr[0] == consts.LeftBrackets && runeArr[len(runeArr)-1] == consts.RightBrackets { // [abc,123]
   399  		desc = string(runeArr[1 : len(runeArr)-1])
   400  		items = strings.Split(desc, ",")
   401  
   402  	} else {
   403  		items = append(items, desc)
   404  	}
   405  
   406  	return
   407  }
   408  
   409  /*
   410  *
   411  
   412  		convert range item to entity, step, repeat
   413  		[user1,user2]{2} -> entry  =>[user1,user2]
   414  	                        step   =>1
   415  	                        repeat =>2
   416  */
   417  func (s *RangeService) ParseRangeSection(rang string) (entry string, step string, repeat int, repeatTag string) {
   418  	rang = strings.TrimSpace(rang)
   419  
   420  	if rang == "" {
   421  		repeat = 1
   422  		return
   423  	}
   424  
   425  	runeArr := []rune(rang)
   426  	if (runeArr[0] == consts.Backtick && runeArr[len(runeArr)-1] == consts.Backtick) || // `xxx`
   427  		(string(runeArr[0]) == string(consts.LeftBrackets) && // (xxx)
   428  			string(runeArr[len(runeArr)-1]) == string(consts.RightBrackets)) {
   429  
   430  		entry = rang
   431  		if repeat == 0 {
   432  			repeat = 1
   433  		}
   434  		return
   435  	}
   436  
   437  	repeat, repeatTag, rangWithoutRepeat := s.ParseRepeat(rang)
   438  
   439  	sectionArr := strings.Split(rangWithoutRepeat, ":")
   440  	entry = sectionArr[0]
   441  	if len(sectionArr) == 2 {
   442  		step = strings.TrimSpace(strings.ToLower(sectionArr[1]))
   443  	}
   444  
   445  	if step != "" {
   446  		pattern := "\\d+"
   447  		isNum, _ := regexp.MatchString(pattern, step)
   448  		if !isNum && step != "r" {
   449  			entry = rang
   450  			step = ""
   451  		}
   452  	}
   453  
   454  	if repeat == 0 {
   455  		repeat = 1
   456  	}
   457  	return entry, step, repeat, repeatTag
   458  }
   459  
   460  /*
   461  *
   462  
   463  		get range item entity's type and desc
   464  		1-9 or [1-9]  -> type => interval
   465  	                     desc => 1-9 or [1-9]
   466  		[user1,user2] -> type => literal
   467  	                     desc => user2,user3
   468  */
   469  func (s *RangeService) ParseRangeSectionDesc(str string) (typ string, desc string) {
   470  	desc = strings.TrimSpace(str)
   471  	runeArr := []rune(desc)
   472  
   473  	if desc == "" {
   474  		typ = "literal"
   475  		return
   476  	}
   477  
   478  	if stringUtils.EndWith(desc, ".yaml") { // refer to another yaml file
   479  		typ = "yaml"
   480  		return
   481  	}
   482  
   483  	if string(runeArr[0]) == string(consts.LeftBrackets) && // [a-z,1-9,userA,UserB]
   484  		string(runeArr[len(runeArr)-1]) == string(consts.RightBrackets) {
   485  
   486  		desc = s.removeBoundary(desc)
   487  		arr := strings.Split(desc, ",")
   488  
   489  		temp := ""
   490  		for _, item := range arr {
   491  			if isScopeStr(item) && s.isCharOrNumberScope(item) { // only support a-z and 0-9 in []
   492  				tempField := domain.DefField{}
   493  				values := s.CreateValuesFromInterval(&tempField, item, "", 1, "")
   494  
   495  				for _, val := range values {
   496  					temp += helper.InterfaceToStr(val) + ","
   497  				}
   498  			} else {
   499  				temp += item + ","
   500  			}
   501  		}
   502  
   503  		temp = strings.TrimSuffix(temp, ",")
   504  		desc = string(consts.LeftBrackets) + temp + string(consts.RightBrackets)
   505  		typ = "literal"
   506  
   507  		return
   508  	}
   509  
   510  	if strings.Contains(desc, ",") || strings.Contains(desc, "`") || !strings.Contains(desc, "-") {
   511  		typ = "literal"
   512  	} else {
   513  		temp := s.removeBoundary(desc)
   514  
   515  		if isScopeStr(temp) {
   516  			typ = "interval"
   517  			desc = temp
   518  		} else {
   519  			typ = "literal"
   520  		}
   521  	}
   522  
   523  	return
   524  }
   525  
   526  func (s *RangeService) removeBoundary(str string) string {
   527  	str = strings.TrimLeft(str, string(consts.LeftBrackets))
   528  	str = strings.TrimRight(str, string(consts.RightBrackets))
   529  
   530  	return str
   531  }
   532  
   533  func isScopeStr(str string) bool {
   534  	arr := strings.Split(str, "-")
   535  	if len(arr) < 2 || strings.TrimSpace(str) == "-" || arr[0] == "" || arr[len(arr)-1] == "" {
   536  		return false
   537  	}
   538  
   539  	left := strings.TrimSpace(arr[0])
   540  	right := strings.TrimSpace(arr[1])
   541  
   542  	if len(left) != 1 || len(right) != 1 { // more than on char, must be number
   543  		leftRune := []rune(string(left[0]))[0]
   544  		rightRune := []rune(string(right[0]))[0]
   545  
   546  		if unicode.IsNumber(leftRune) && unicode.IsNumber(rightRune) {
   547  			return true
   548  		} else {
   549  			return false
   550  		}
   551  	} else {
   552  		leftRune := []rune(string(left[0]))[0]
   553  		rightRune := []rune(string(right[0]))[0]
   554  
   555  		if (unicode.IsLetter(leftRune) && unicode.IsLetter(rightRune)) ||
   556  			(unicode.IsNumber(leftRune) && unicode.IsNumber(rightRune)) {
   557  			return true
   558  		} else {
   559  			return false
   560  		}
   561  	}
   562  }
   563  
   564  func (s *RangeService) isCharOrNumberScope(str string) bool {
   565  	arr := strings.Split(str, "-")
   566  	if len(arr) < 2 {
   567  		return false
   568  	}
   569  
   570  	left := strings.TrimSpace(arr[0])
   571  	right := strings.TrimSpace(arr[1])
   572  
   573  	if len(left) == 1 && len(right) == 1 {
   574  		return true
   575  	}
   576  
   577  	return false
   578  }
   579  
   580  func (s *RangeService) ParseRepeat(rang string) (repeat int, repeatTag, rangeWithoutRepeat string) {
   581  	repeat = 1
   582  
   583  	regx := regexp.MustCompile(`\{(.*)!?\}`)
   584  	arr := regx.FindStringSubmatch(rang)
   585  	tag := ""
   586  	if len(arr) == 2 {
   587  		str := strings.TrimSpace(arr[1])
   588  		if str[len(str)-1:] == "!" {
   589  			tag = str[len(str)-1:]
   590  			str = strings.TrimSpace(str[:len(str)-1])
   591  		}
   592  		repeat, _ = strconv.Atoi(str)
   593  	}
   594  	repeatTag = tag
   595  	rangeWithoutRepeat = regx.ReplaceAllString(rang, "")
   596  
   597  	return
   598  }
   599  
   600  func (s *RangeService) CheckRangeType(startStr string, endStr string, stepStr string) (dataType string, step interface{}, precision int,
   601  	rand bool, count int) {
   602  
   603  	stepStr = strings.ToLower(strings.TrimSpace(stepStr))
   604  
   605  	if start, end, stepi, ok := s.checkRangeTypeIsInt(startStr, endStr, stepStr); ok { // is int
   606  		step = 1
   607  		if stepStr == "r" {
   608  			rand = true
   609  		}
   610  
   611  		count = (int)(start-end) / int(stepi)
   612  		if count < 0 {
   613  			count = count * -1
   614  		}
   615  
   616  		dataType = "int"
   617  		step = int(stepi)
   618  		return
   619  	} else if start, end, stepf, ok := s.checkRangeTypeIsFloat(startStr, endStr, stepStr); ok { // is float
   620  		step = stepf
   621  
   622  		if stepStr == "r" {
   623  			rand = true
   624  		}
   625  
   626  		precision1, step1 := helper.GetPrecision(start, step)
   627  		precision2, step2 := helper.GetPrecision(end, step)
   628  		if precision1 < precision2 {
   629  			precision = precision2
   630  			step = step2
   631  		} else {
   632  			precision = precision1
   633  			step = step1
   634  		}
   635  
   636  		if (start > end && stepf > 0) || (start < end && stepf < 0) {
   637  			step = -1 * stepf
   638  		}
   639  
   640  		dataType = "float"
   641  		count = int(math.Floor(math.Abs(start-end)/stepf + 0.5))
   642  		return
   643  
   644  	} else if len(startStr) == 1 && len(endStr) == 1 { // is char
   645  		step = 1
   646  
   647  		if stepStr != "r" {
   648  			stepChar, errChar3 := strconv.Atoi(stepStr)
   649  			if errChar3 == nil {
   650  				step = stepChar
   651  			}
   652  		} else if stepStr == "r" {
   653  			rand = true
   654  		}
   655  
   656  		if (strings.Compare(startStr, endStr) > 0 && step.(int) > 0) ||
   657  			(strings.Compare(startStr, endStr) < 0 && step.(int) < 0) {
   658  			step = -1 * step.(int)
   659  		}
   660  
   661  		dataType = "char"
   662  
   663  		startChar := startStr[0]
   664  		endChar := endStr[0]
   665  
   666  		gap := 0
   667  		if endChar > startChar { // 负数转uint单独处理
   668  			gap = int(endChar - startChar)
   669  		} else {
   670  			gap = int(startChar - endChar)
   671  		}
   672  		count = gap / step.(int)
   673  		if count < 0 {
   674  			count = count * -1
   675  		}
   676  		return
   677  	}
   678  
   679  	// else is string
   680  	dataType = "string"
   681  	step = 1
   682  	return
   683  }
   684  
   685  func (s *RangeService) checkRangeTypeIsInt(startStr string, endStr string, stepStr string) (
   686  	start int64, end int64, step int64, ok bool) {
   687  	step = 1
   688  
   689  	stepStr = strings.ToLower(strings.TrimSpace(stepStr))
   690  
   691  	start, errInt1 := strconv.ParseInt(startStr, 0, 64)
   692  	end, errInt2 := strconv.ParseInt(endStr, 0, 64)
   693  	var errInt3 error
   694  
   695  	if stepStr != "" && stepStr != "r" {
   696  		step, errInt3 = strconv.ParseInt(stepStr, 0, 64)
   697  	}
   698  
   699  	if errInt1 == nil && errInt2 == nil && errInt3 == nil { // is int
   700  		if (start > end && step > 0) || (start < end && step < 0) {
   701  			step = -1 * step
   702  		}
   703  
   704  		ok = true
   705  		return
   706  
   707  	}
   708  
   709  	return
   710  }
   711  
   712  func (s *RangeService) checkRangeTypeIsFloat(startStr string, endStr string, stepStr string) (
   713  	start float64, end float64, step float64, ok bool) {
   714  
   715  	stepStr = strings.ToLower(strings.TrimSpace(stepStr))
   716  
   717  	start, errFloat1 := strconv.ParseFloat(startStr, 64)
   718  	end, errFloat2 := strconv.ParseFloat(endStr, 64)
   719  	var errFloat3 error
   720  
   721  	if stepStr != "" && stepStr != "r" {
   722  		step, errFloat3 = strconv.ParseFloat(stepStr, 64)
   723  	} else {
   724  		step = 0
   725  	}
   726  
   727  	if errFloat1 == nil && errFloat2 == nil && errFloat3 == nil { // is float
   728  		if (start > end && step > 0) || (start < end && step < 0) {
   729  			step = -1 * step
   730  		}
   731  
   732  		ok = true
   733  		return
   734  	}
   735  
   736  	return
   737  }
   738  
   739  func (s *RangeService) GetRandFieldSection(pth string) (key int) {
   740  	max := 0
   741  
   742  	for k, v := range vari.GlobalVars.RandFieldSectionShortKeysToPathMap {
   743  		if pth == v {
   744  			key = k
   745  			return
   746  		}
   747  
   748  		if k > max {
   749  			max = k
   750  		}
   751  	}
   752  
   753  	if key == 0 {
   754  		key = max + 1
   755  	}
   756  
   757  	return
   758  }