func (s SafeFunctionSignature) Part() string {
	return s.part
}
Part sets the part of the file/path that is matched [ filename content extension ]
package core
import (
	"fmt"
	"gopkg.in/src-d/go-git.v4/plumbing/object"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"math"
	"os"
	"regexp"
	"strconv"
	"strings"
)
const (
	PartExtension = "extension"  
	PartFilename  = "filename"   
	PartPath      = "path"       
	PartContent   = "content"    
)
var Signatures []Signature
var SafeFunctionSignatures []SafeFunctionSignature
func loadSignatureSet(filename string) (SignatureConfig, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return SignatureConfig{}, err
	}
	var c SignatureConfig
	err = yaml.Unmarshal(bytes, &c)
	if err != nil {
		return SignatureConfig{}, err
	}
	return c, nil
}
func getEntropyInt(s string) float64 {
	m := map[rune]float64{}
	for _, r := range s {
		m[r]++
	}
	var hm float64
	for _, c := range m {
		hm += c * math.Log2(c)
	}
	l := float64(len(s))
	res := math.Log2(l) - hm/l
	return res
}
type Signature interface {
	Description() string
	Enable() int
	ExtractMatch(file MatchFile, sess *Session, change *object.Change) (bool, map[string]int)
	ConfidenceLevel() int
	Part() string
	SignatureID() string  
}
type SignaturesMetaData struct {
	Date    string
	Time    int
	Version string
}
type SafeFunctionSignature struct {
	comment         string
	description     string
	enable          int
	entropy         float64
	match           *regexp.Regexp
	confidenceLevel int
	part            string
	signatureid     string
}
type SimpleSignature struct {
	comment         string
	description     string
	enable          int
	entropy         float64
	match           string
	confidenceLevel int
	part            string
	signatureid     string
}
type PatternSignature struct {
	comment         string
	description     string
	enable          int
	entropy         float64
	match           *regexp.Regexp
	confidenceLevel int
	part            string
	signatureid     string
}
type SignatureDef struct {
	Comment         string  `yaml:"comment"`
	Description     string  `yaml:"description"`
	Enable          int     `yaml:"enable"`
	Entropy         float64 `yaml:"entropy"`
	Match           string  `yaml:"match"`
	ConfidenceLevel int     `yaml:"confidence-level"`
	Part            string  `yaml:"part"`
	SignatureID     string  `yaml:"signatureid"`
}
type SignatureConfig struct {
	Meta                   SignaturesMetaData `yaml:"Meta"`
	PatternSignatures      []SignatureDef     `yaml:"PatternSignatures"`
	SimpleSignatures       []SignatureDef     `yaml:"SimpleSignatures"`
	SafeFunctionSignatures []SignatureDef     `yaml:"SafeFunctionSignatures"`
}
func (s SimpleSignature) ExtractMatch(file MatchFile, sess *Session, change *object.Change) (bool, map[string]int) {
	var haystack *string
	var bResult = false
	var results map[string]int
	switch s.part {
	case PartPath:
		haystack = &file.Path
		bResult = true
	case PartFilename:
		haystack = &file.Filename
		bResult = true
	case PartExtension:
		haystack = &file.Extension
		bResult = true
	default:
		return bResult, results
	}
	return s.match == *haystack, results
}
func (s SimpleSignature) Enable() int {
	return s.enable
}
func (s SimpleSignature) ConfidenceLevel() int {
	return s.confidenceLevel
}
func (s SimpleSignature) Part() string {
	return s.part
}
func (s SimpleSignature) Description() string {
	return s.description
}
func (s SimpleSignature) SignatureID() string {
	return s.signatureid
}
func IsSafeText(sMatchString *string) bool {
	bResult := false
	for _, safeSig := range SafeFunctionSignatures {
		if safeSig.match.MatchString(*sMatchString) {
			bResult = true
		}
	}
	return bResult
}
func confirmEntropy(thisMatch string, iSessionEntropy float64) bool {
	bResult := false
	iEntropy := getEntropyInt(thisMatch)
	if (iSessionEntropy == 0) || (iEntropy >= iSessionEntropy) {
		if !IsSafeText(&thisMatch) {
			bResult = true
		}
	}
	return bResult
}
func (s PatternSignature) ExtractMatch(file MatchFile, sess *Session, change *object.Change) (bool, map[string]int) {
	var haystack *string             
	var bResult = false              
	results := make(map[string]int)  
	switch s.part {
	case PartPath:
		haystack = &file.Path
		bResult = s.match.MatchString(*haystack)
	case PartFilename:
		haystack = &file.Filename
		bResult = s.match.MatchString(*haystack)
	case PartExtension:
		haystack = &file.Extension
		bResult = s.match.MatchString(*haystack)
	case PartContent:
		haystack := &file.Path
		if PathExists(*haystack, sess) {
			if _, err := os.Stat(*haystack); err == nil {
				data, err := ioutil.ReadFile(*haystack)
				if err != nil {
					sErrAppend := fmt.Sprintf("ERROR --- Unable to open file for scanning: <%s> \nError Message: <%s>", *haystack, err)
					results[sErrAppend] = 0  
					return false, results
				}
				r := s.match
				var contextMatches []string
				if r.Match(data) {
					for _, curRegexMatch := range r.FindAll(data, -1) {
						contextMatches = append(contextMatches, string(curRegexMatch))
					}
					if len(contextMatches) > 0 {
						bResult = true
						for i, curMatch := range contextMatches {
							thisMatch := string(curMatch[:])
							thisMatch = strings.TrimSuffix(thisMatch, "\n")
							bResult = confirmEntropy(thisMatch, s.entropy)
							if bResult {
								linesOfScannedFile := strings.Split(string(data), "\n")
								num := fetchLineNumber(&linesOfScannedFile, thisMatch, 0)
								results[strconv.Itoa(i)+"_"+thisMatch] = num
							}
						}
						return bResult, results
					}
				}
				if sess.ScanType != "localPath" {
					content, err := GetChangeContent(change)
					if err != nil {
						sess.Out.Error("Error retrieving content in commit %s, change %s:  %s\n", "commit.String()", change.String(), err)
					}
					if r.Match([]byte(content)) {
						for _, curRegexMatch := range r.FindAll([]byte(content), -1) {
							contextMatches = append(contextMatches, string(curRegexMatch))
						}
						if len(contextMatches) > 0 {
							bResult = true
							for i, curMatch := range contextMatches {
								thisMatch := string(curMatch[:])
								thisMatch = strings.TrimSuffix(thisMatch, "\n")
								bResult = confirmEntropy(thisMatch, s.entropy)
								if bResult {
									linesOfScannedFile := strings.Split(content, "\n")
									num := fetchLineNumber(&linesOfScannedFile, thisMatch, i)
									results[strconv.Itoa(i)+"_"+thisMatch] = num
								}
							}
							return bResult, results
						}
					}
				}
			}
		}
	default:  
		return bResult, results
	}
	return bResult, results
}
func fetchLineNumber(input *[]string, thisMatch string, idx int) int {
	linesOfScannedFile := *input
	lineNumIndexMap := make(map[int]int)
	count := 0
	for i, line := range linesOfScannedFile {
		if strings.Contains(line, thisMatch) {
			lineNumIndexMap[count] = i + 1
			count = count + 1
		}
	}
	return lineNumIndexMap[idx]
}
func (s PatternSignature) Enable() int {
	return s.enable
}
func (s PatternSignature) ConfidenceLevel() int {
	return s.confidenceLevel
}
func (s PatternSignature) Part() string {
	return s.part
}
func (s PatternSignature) Description() string {
	return s.description
}
func (s PatternSignature) SignatureID() string {
	return s.signatureid
}
func (s SafeFunctionSignature) Enable() int {
	return s.enable
}
func (s SafeFunctionSignature) ConfidenceLevel() int {
	return s.confidenceLevel
}