mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 03:18:24 +00:00 
			
		
		
		
	* Dump: Use mholt/archive/v3 to support tar including many compressions Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: Allow dump output to stdout Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: Fixed bug present since #6677 where SessionConfig.Provider is never "file" Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: never pack RepoRootPath, LFS.ContentPath and LogRootPath when they are below AppDataPath Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: also dump LFS (fixes #10058) Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: never dump CustomPath if CustomPath is a subdir of or equal to AppDataPath (fixes #10365) Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Use log.Info instead of fmt.Fprintf Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * import ordering * make fmt Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: Matti R <matti@mdranta.net>
		
			
				
	
	
		
			642 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			642 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| package brotli
 | |
| 
 | |
| const (
 | |
| 	transformIdentity       = 0
 | |
| 	transformOmitLast1      = 1
 | |
| 	transformOmitLast2      = 2
 | |
| 	transformOmitLast3      = 3
 | |
| 	transformOmitLast4      = 4
 | |
| 	transformOmitLast5      = 5
 | |
| 	transformOmitLast6      = 6
 | |
| 	transformOmitLast7      = 7
 | |
| 	transformOmitLast8      = 8
 | |
| 	transformOmitLast9      = 9
 | |
| 	transformUppercaseFirst = 10
 | |
| 	transformUppercaseAll   = 11
 | |
| 	transformOmitFirst1     = 12
 | |
| 	transformOmitFirst2     = 13
 | |
| 	transformOmitFirst3     = 14
 | |
| 	transformOmitFirst4     = 15
 | |
| 	transformOmitFirst5     = 16
 | |
| 	transformOmitFirst6     = 17
 | |
| 	transformOmitFirst7     = 18
 | |
| 	transformOmitFirst8     = 19
 | |
| 	transformOmitFirst9     = 20
 | |
| 	transformShiftFirst     = 21
 | |
| 	transformShiftAll       = 22 + iota - 22
 | |
| 	numTransformTypes
 | |
| )
 | |
| 
 | |
| const transformsMaxCutOff = transformOmitLast9
 | |
| 
 | |
| type transforms struct {
 | |
| 	prefix_suffix_size uint16
 | |
| 	prefix_suffix      []byte
 | |
| 	prefix_suffix_map  []uint16
 | |
| 	num_transforms     uint32
 | |
| 	transforms         []byte
 | |
| 	params             []byte
 | |
| 	cutOffTransforms   [transformsMaxCutOff + 1]int16
 | |
| }
 | |
| 
 | |
| func transformPrefixId(t *transforms, I int) byte {
 | |
| 	return t.transforms[(I*3)+0]
 | |
| }
 | |
| 
 | |
| func transformType(t *transforms, I int) byte {
 | |
| 	return t.transforms[(I*3)+1]
 | |
| }
 | |
| 
 | |
| func transformSuffixId(t *transforms, I int) byte {
 | |
| 	return t.transforms[(I*3)+2]
 | |
| }
 | |
| 
 | |
| func transformPrefix(t *transforms, I int) []byte {
 | |
| 	return t.prefix_suffix[t.prefix_suffix_map[transformPrefixId(t, I)]:]
 | |
| }
 | |
| 
 | |
| func transformSuffix(t *transforms, I int) []byte {
 | |
| 	return t.prefix_suffix[t.prefix_suffix_map[transformSuffixId(t, I)]:]
 | |
| }
 | |
| 
 | |
| /* RFC 7932 transforms string data */
 | |
| const kPrefixSuffix string = "\001 \002, \010 of the \004 of \002s \001.\005 and \004 " + "in \001\"\004 to \002\">\001\n\002. \001]\005 for \003 a \006 " + "that \001'\006 with \006 from \004 by \001(\006. T" + "he \004 on \004 as \004 is \004ing \002\n\t\001:\003ed " + "\002=\"\004 at \003ly \001,\002='\005.com/\007. This \005" + " not \003er \003al \004ful \004ive \005less \004es" + "t \004ize \002\xc2\xa0\004ous \005 the \002e \000"
 | |
| 
 | |
| var kPrefixSuffixMap = [50]uint16{
 | |
| 	0x00,
 | |
| 	0x02,
 | |
| 	0x05,
 | |
| 	0x0E,
 | |
| 	0x13,
 | |
| 	0x16,
 | |
| 	0x18,
 | |
| 	0x1E,
 | |
| 	0x23,
 | |
| 	0x25,
 | |
| 	0x2A,
 | |
| 	0x2D,
 | |
| 	0x2F,
 | |
| 	0x32,
 | |
| 	0x34,
 | |
| 	0x3A,
 | |
| 	0x3E,
 | |
| 	0x45,
 | |
| 	0x47,
 | |
| 	0x4E,
 | |
| 	0x55,
 | |
| 	0x5A,
 | |
| 	0x5C,
 | |
| 	0x63,
 | |
| 	0x68,
 | |
| 	0x6D,
 | |
| 	0x72,
 | |
| 	0x77,
 | |
| 	0x7A,
 | |
| 	0x7C,
 | |
| 	0x80,
 | |
| 	0x83,
 | |
| 	0x88,
 | |
| 	0x8C,
 | |
| 	0x8E,
 | |
| 	0x91,
 | |
| 	0x97,
 | |
| 	0x9F,
 | |
| 	0xA5,
 | |
| 	0xA9,
 | |
| 	0xAD,
 | |
| 	0xB2,
 | |
| 	0xB7,
 | |
| 	0xBD,
 | |
| 	0xC2,
 | |
| 	0xC7,
 | |
| 	0xCA,
 | |
| 	0xCF,
 | |
| 	0xD5,
 | |
| 	0xD8,
 | |
| }
 | |
| 
 | |
| /* RFC 7932 transforms */
 | |
| var kTransformsData = []byte{
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	0,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformOmitFirst1,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	47,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	49,
 | |
| 	4,
 | |
| 	transformIdentity,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	3,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	6,
 | |
| 	49,
 | |
| 	transformOmitFirst2,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformOmitLast1,
 | |
| 	49,
 | |
| 	1,
 | |
| 	transformIdentity,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	1,
 | |
| 	0,
 | |
| 	transformUppercaseFirst,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	7,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	9,
 | |
| 	48,
 | |
| 	transformIdentity,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	8,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	5,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	10,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	11,
 | |
| 	49,
 | |
| 	transformOmitLast3,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	13,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	14,
 | |
| 	49,
 | |
| 	transformOmitFirst3,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformOmitLast2,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	15,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	16,
 | |
| 	0,
 | |
| 	transformUppercaseFirst,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	12,
 | |
| 	5,
 | |
| 	transformIdentity,
 | |
| 	49,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	1,
 | |
| 	49,
 | |
| 	transformOmitFirst4,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	18,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	17,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	19,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	20,
 | |
| 	49,
 | |
| 	transformOmitFirst5,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformOmitFirst6,
 | |
| 	49,
 | |
| 	47,
 | |
| 	transformIdentity,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformOmitLast4,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	22,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	23,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	24,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	25,
 | |
| 	49,
 | |
| 	transformOmitLast7,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformOmitLast1,
 | |
| 	26,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	27,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	28,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	12,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	29,
 | |
| 	49,
 | |
| 	transformOmitFirst9,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformOmitFirst7,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformOmitLast6,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	21,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	1,
 | |
| 	49,
 | |
| 	transformOmitLast8,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	31,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	32,
 | |
| 	47,
 | |
| 	transformIdentity,
 | |
| 	3,
 | |
| 	49,
 | |
| 	transformOmitLast5,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformOmitLast9,
 | |
| 	49,
 | |
| 	0,
 | |
| 	transformUppercaseFirst,
 | |
| 	1,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	8,
 | |
| 	5,
 | |
| 	transformIdentity,
 | |
| 	21,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	10,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	30,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	5,
 | |
| 	35,
 | |
| 	transformIdentity,
 | |
| 	49,
 | |
| 	47,
 | |
| 	transformIdentity,
 | |
| 	2,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	17,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	36,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	33,
 | |
| 	5,
 | |
| 	transformIdentity,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	21,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	5,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	37,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	30,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	38,
 | |
| 	0,
 | |
| 	transformUppercaseAll,
 | |
| 	0,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	39,
 | |
| 	0,
 | |
| 	transformUppercaseAll,
 | |
| 	49,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	34,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	8,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	12,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	21,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	40,
 | |
| 	0,
 | |
| 	transformUppercaseFirst,
 | |
| 	12,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	41,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	42,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	17,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	43,
 | |
| 	0,
 | |
| 	transformUppercaseFirst,
 | |
| 	5,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	10,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	34,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	33,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	44,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	5,
 | |
| 	45,
 | |
| 	transformIdentity,
 | |
| 	49,
 | |
| 	0,
 | |
| 	transformIdentity,
 | |
| 	33,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	30,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	30,
 | |
| 	49,
 | |
| 	transformIdentity,
 | |
| 	46,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	1,
 | |
| 	49,
 | |
| 	transformUppercaseFirst,
 | |
| 	34,
 | |
| 	0,
 | |
| 	transformUppercaseFirst,
 | |
| 	33,
 | |
| 	0,
 | |
| 	transformUppercaseAll,
 | |
| 	30,
 | |
| 	0,
 | |
| 	transformUppercaseAll,
 | |
| 	1,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	33,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	21,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	12,
 | |
| 	0,
 | |
| 	transformUppercaseAll,
 | |
| 	5,
 | |
| 	49,
 | |
| 	transformUppercaseAll,
 | |
| 	34,
 | |
| 	0,
 | |
| 	transformUppercaseAll,
 | |
| 	12,
 | |
| 	0,
 | |
| 	transformUppercaseFirst,
 | |
| 	30,
 | |
| 	0,
 | |
| 	transformUppercaseAll,
 | |
| 	34,
 | |
| 	0,
 | |
| 	transformUppercaseFirst,
 | |
| 	34,
 | |
| }
 | |
| 
 | |
| var kBrotliTransforms = transforms{
 | |
| 	217,
 | |
| 	[]byte(kPrefixSuffix),
 | |
| 	kPrefixSuffixMap[:],
 | |
| 	121,
 | |
| 	kTransformsData,
 | |
| 	nil, /* no extra parameters */
 | |
| 	[transformsMaxCutOff + 1]int16{0, 12, 27, 23, 42, 63, 56, 48, 59, 64},
 | |
| }
 | |
| 
 | |
| func getTransforms() *transforms {
 | |
| 	return &kBrotliTransforms
 | |
| }
 | |
| 
 | |
| func toUpperCase(p []byte) int {
 | |
| 	if p[0] < 0xC0 {
 | |
| 		if p[0] >= 'a' && p[0] <= 'z' {
 | |
| 			p[0] ^= 32
 | |
| 		}
 | |
| 
 | |
| 		return 1
 | |
| 	}
 | |
| 
 | |
| 	/* An overly simplified uppercasing model for UTF-8. */
 | |
| 	if p[0] < 0xE0 {
 | |
| 		p[1] ^= 32
 | |
| 		return 2
 | |
| 	}
 | |
| 
 | |
| 	/* An arbitrary transform for three byte characters. */
 | |
| 	p[2] ^= 5
 | |
| 
 | |
| 	return 3
 | |
| }
 | |
| 
 | |
| func shiftTransform(word []byte, word_len int, parameter uint16) int {
 | |
| 	/* Limited sign extension: scalar < (1 << 24). */
 | |
| 	var scalar uint32 = (uint32(parameter) & 0x7FFF) + (0x1000000 - (uint32(parameter) & 0x8000))
 | |
| 	if word[0] < 0x80 {
 | |
| 		/* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
 | |
| 		scalar += uint32(word[0])
 | |
| 
 | |
| 		word[0] = byte(scalar & 0x7F)
 | |
| 		return 1
 | |
| 	} else if word[0] < 0xC0 {
 | |
| 		/* Continuation / 10AAAAAA. */
 | |
| 		return 1
 | |
| 	} else if word[0] < 0xE0 {
 | |
| 		/* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
 | |
| 		if word_len < 2 {
 | |
| 			return 1
 | |
| 		}
 | |
| 		scalar += uint32(word[1]&0x3F | (word[0]&0x1F)<<6)
 | |
| 		word[0] = byte(0xC0 | (scalar>>6)&0x1F)
 | |
| 		word[1] = byte(uint32(word[1]&0xC0) | scalar&0x3F)
 | |
| 		return 2
 | |
| 	} else if word[0] < 0xF0 {
 | |
| 		/* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
 | |
| 		if word_len < 3 {
 | |
| 			return word_len
 | |
| 		}
 | |
| 		scalar += uint32(word[2])&0x3F | uint32(word[1]&0x3F)<<6 | uint32(word[0]&0x0F)<<12
 | |
| 		word[0] = byte(0xE0 | (scalar>>12)&0x0F)
 | |
| 		word[1] = byte(uint32(word[1]&0xC0) | (scalar>>6)&0x3F)
 | |
| 		word[2] = byte(uint32(word[2]&0xC0) | scalar&0x3F)
 | |
| 		return 3
 | |
| 	} else if word[0] < 0xF8 {
 | |
| 		/* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
 | |
| 		if word_len < 4 {
 | |
| 			return word_len
 | |
| 		}
 | |
| 		scalar += uint32(word[3])&0x3F | uint32(word[2]&0x3F)<<6 | uint32(word[1]&0x3F)<<12 | uint32(word[0]&0x07)<<18
 | |
| 		word[0] = byte(0xF0 | (scalar>>18)&0x07)
 | |
| 		word[1] = byte(uint32(word[1]&0xC0) | (scalar>>12)&0x3F)
 | |
| 		word[2] = byte(uint32(word[2]&0xC0) | (scalar>>6)&0x3F)
 | |
| 		word[3] = byte(uint32(word[3]&0xC0) | scalar&0x3F)
 | |
| 		return 4
 | |
| 	}
 | |
| 
 | |
| 	return 1
 | |
| }
 | |
| 
 | |
| func transformDictionaryWord(dst []byte, word []byte, len int, trans *transforms, transform_idx int) int {
 | |
| 	var idx int = 0
 | |
| 	var prefix []byte = transformPrefix(trans, transform_idx)
 | |
| 	var type_ byte = transformType(trans, transform_idx)
 | |
| 	var suffix []byte = transformSuffix(trans, transform_idx)
 | |
| 	{
 | |
| 		var prefix_len int = int(prefix[0])
 | |
| 		prefix = prefix[1:]
 | |
| 		for {
 | |
| 			tmp1 := prefix_len
 | |
| 			prefix_len--
 | |
| 			if tmp1 == 0 {
 | |
| 				break
 | |
| 			}
 | |
| 			dst[idx] = prefix[0]
 | |
| 			idx++
 | |
| 			prefix = prefix[1:]
 | |
| 		}
 | |
| 	}
 | |
| 	{
 | |
| 		var t int = int(type_)
 | |
| 		var i int = 0
 | |
| 		if t <= transformOmitLast9 {
 | |
| 			len -= t
 | |
| 		} else if t >= transformOmitFirst1 && t <= transformOmitFirst9 {
 | |
| 			var skip int = t - (transformOmitFirst1 - 1)
 | |
| 			word = word[skip:]
 | |
| 			len -= skip
 | |
| 		}
 | |
| 
 | |
| 		for i < len {
 | |
| 			dst[idx] = word[i]
 | |
| 			idx++
 | |
| 			i++
 | |
| 		}
 | |
| 		if t == transformUppercaseFirst {
 | |
| 			toUpperCase(dst[idx-len:])
 | |
| 		} else if t == transformUppercaseAll {
 | |
| 			var uppercase []byte = dst
 | |
| 			uppercase = uppercase[idx-len:]
 | |
| 			for len > 0 {
 | |
| 				var step int = toUpperCase(uppercase)
 | |
| 				uppercase = uppercase[step:]
 | |
| 				len -= step
 | |
| 			}
 | |
| 		} else if t == transformShiftFirst {
 | |
| 			var param uint16 = uint16(trans.params[transform_idx*2]) + uint16(trans.params[transform_idx*2+1])<<8
 | |
| 			shiftTransform(dst[idx-len:], int(len), param)
 | |
| 		} else if t == transformShiftAll {
 | |
| 			var param uint16 = uint16(trans.params[transform_idx*2]) + uint16(trans.params[transform_idx*2+1])<<8
 | |
| 			var shift []byte = dst
 | |
| 			shift = shift[idx-len:]
 | |
| 			for len > 0 {
 | |
| 				var step int = shiftTransform(shift, int(len), param)
 | |
| 				shift = shift[step:]
 | |
| 				len -= step
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	{
 | |
| 		var suffix_len int = int(suffix[0])
 | |
| 		suffix = suffix[1:]
 | |
| 		for {
 | |
| 			tmp2 := suffix_len
 | |
| 			suffix_len--
 | |
| 			if tmp2 == 0 {
 | |
| 				break
 | |
| 			}
 | |
| 			dst[idx] = suffix[0]
 | |
| 			idx++
 | |
| 			suffix = suffix[1:]
 | |
| 		}
 | |
| 		return idx
 | |
| 	}
 | |
| }
 |