Remixware report: shopfront
Code in this project that matches third-party code, the licence that code came with, and what that licence asks.
- Project
- testdata/projects/shopfront
- Project licence
- MIT
- Compared with
- upstream.rmx (index: 10 components, 10 files); shopfront.json (SCANOSS results: 4 matches)
- Scanned
- 11 source files, 474 lines
- Notice files
- THIRD_PARTY_NOTICES.md
- Made
- 2026-10-26T14:06:45Z by remixware 0.2.0
Findings
GPL-3.0-or-later code can't go into an MIT project unless the whole program is released under GPL-3.0-or-later. Remove it, rewrite it, or relicense.
Your code
7func lessNatural(left, right string) bool { 8 p, q := 0, 0 9 for p < len(left) && q < len(right) { 10 x, y := left[p], right[q] 11 if digit(x) && digit(y) { 12 startP := p 13 for p < len(left) && digit(left[p]) { 14 p++ 15 } 16 startQ := q 17 for q < len(right) && digit(right[q]) { 18 q++ 19 } 20 numL := dropZeros(left[startP:p]) 21 numR := dropZeros(right[startQ:q]) 22 if len(numL) != len(numR) { 23 return len(numL) < len(numR) 24 } 25 if numL != numR { 26 return numL < numR 27 } 28 continue 29 } 30 if x != y { 31 return x < y 32 } 33 p++ 34 q++ 35 } 36 return len(left)-p < len(right)-q 37} 38 39func digit(c byte) bool { return c >= '0' && c <= '9' } 40 41func dropZeros(s string) string { 42 for len(s) > 1 && s[0] == '0' { 43 s = s[1:] 44 } 45 return s 46}
Their code
14func NaturalLess(a, b string) bool { 15 i, j := 0, 0 16 for i < len(a) && j < len(b) { 17 ca, cb := a[i], b[j] 18 if isDigit(ca) && isDigit(cb) { 19 si := i 20 for i < len(a) && isDigit(a[i]) { 21 i++ 22 } 23 sj := j 24 for j < len(b) && isDigit(b[j]) { 25 j++ 26 } 27 na := trimZeros(a[si:i]) 28 nb := trimZeros(b[sj:j]) 29 if len(na) != len(nb) { 30 return len(na) < len(nb) 31 } 32 if na != nb { 33 return na < nb 34 } 35 continue 36 } 37 if ca != cb { 38 return ca < cb 39 } 40 i++ 41 j++ 42 } 43 return len(a)-i < len(b)-j 44} 45 46func isDigit(c byte) bool { return c >= '0' && c <= '9' } 47 48func trimZeros(s string) string { 49 for len(s) > 1 && s[0] == '0' { 50 s = s[1:] 51 } 52 return s 53}
AGPL-3.0-or-later code can't go into an MIT project unless the whole program is released under AGPL-3.0-or-later, which also means offering the source to everyone who uses it over a network.
Your code
1"""Build URL slugs for product pages.""" 2 3import re 4import unicodedata 5 6_STRIP = re.compile(r"[^\w\s-]") 7_DASHES = re.compile(r"[-\s]+") 8 9 10def slugify(title, max_length=60): 11 """Turn a page title into a URL path segment.""" 12 value = unicodedata.normalize("NFKD", title) 13 value = value.encode("ascii", "ignore").decode("ascii") 14 value = _STRIP.sub("", value).strip().lower() 15 value = _DASHES.sub("-", value) 16 if len(value) > max_length: 17 cut = value.rfind("-", 0, max_length) 18 value = value[: cut if cut > 0 else max_length] 19 return value or "page" 20 21 22def escape_html(text, quote=True): 23 """Escape the characters that matter in HTML.""" 24 out = [] 25 for ch in text: 26 if ch == "&": 27 out.append("&") 28 elif ch == "<": 29 out.append("<") 30 elif ch == ">": 31 out.append(">") 32 elif quote and ch == '"': 33 out.append(""") 34 else: 35 out.append(ch) 36 return "".join(out)
Their code
1"""Text helpers for page titles and markup.""" 2 3import re 4import unicodedata 5 6_STRIP = re.compile(r"[^\w\s-]") 7_DASHES = re.compile(r"[-\s]+") 8 9 10def slugify(title, max_length=60): 11 """Turn a page title into a URL path segment.""" 12 value = unicodedata.normalize("NFKD", title) 13 value = value.encode("ascii", "ignore").decode("ascii") 14 value = _STRIP.sub("", value).strip().lower() 15 value = _DASHES.sub("-", value) 16 if len(value) > max_length: 17 cut = value.rfind("-", 0, max_length) 18 value = value[: cut if cut > 0 else max_length] 19 return value or "page" 20 21 22def escape_html(text, quote=True): 23 """Escape the characters that matter in HTML.""" 24 out = [] 25 for ch in text: 26 if ch == "&": 27 out.append("&") 28 elif ch == "<": 29 out.append("<") 30 elif ch == ">": 31 out.append(">") 32 elif quote and ch == '"': 33 out.append(""") 34 else: 35 out.append(ch) 36 return "".join(out)
No licence was found, so nobody has given permission to copy this code. Remove it or ask the author.
Your code
2package format 3 4import ( 5 "fmt" 6 "strings" 7) 8 9// Size formats a file size with binary units. 10func Size(n int64) string { 11 const unit = 1024 12 if n < unit { 13 return fmt.Sprintf("%d B", n) 14 } 15 div, exp := int64(unit), 0 16 for m := n / unit; m >= unit; m /= unit { 17 div *= unit 18 exp++ 19 } 20 value := float64(n) / float64(div) 21 text := fmt.Sprintf("%.1f", value) 22 text = strings.TrimSuffix(text, ".0") 23 return text + " " + string("KMGTPE"[exp]) + "iB" 24}
Their code
1package snippets 2 3import ( 4 "fmt" 5 "strings" 6) 7 8// HumanBytes formats a byte count with binary units: 1536 -> "1.5 KiB". 9func HumanBytes(n int64) string { 10 const unit = 1024 11 if n < unit { 12 return fmt.Sprintf("%d B", n) 13 } 14 div, exp := int64(unit), 0 15 for m := n / unit; m >= unit; m /= unit { 16 div *= unit 17 exp++ 18 } 19 value := float64(n) / float64(div) 20 text := fmt.Sprintf("%.1f", value) 21 text = strings.TrimSuffix(text, ".0") 22 return text + " " + string("KMGTPE"[exp]) + "iB" 23}
No licence information was found for this source. Check its repository before keeping the copy.
MPL-2.0 applies file by file: keep the copied code in its own file under MPL-2.0, keep its notice, and publish your changes to that file. Its copyright line and licence text also have to ship with your copy: until your notices carry them, this counts as attribution missing.
Your code
2package cache 3 4import "container/list" 5 6type item struct { 7 key string 8 value any 9} 10 11// Products keeps at most size products and drops the least recently used. 12type Products struct { 13 size int 14 order *list.List 15 items map[string]*list.Element 16 evict func(key string, value any) 17} 18 19// NewProducts returns an empty cache. 20func NewProducts(size int, evict func(key string, value any)) *Products { 21 return &Products{size: size, order: list.New(), items: make(map[string]*list.Element), evict: evict} 22} 23 24// Get returns the value for key and marks it as recently used. 25func (c *Products) Get(key string) (any, bool) { 26 el, ok := c.items[key] 27 if !ok { 28 return nil, false 29 } 30 c.order.MoveToFront(el) 31 return el.Value.(*item).value, true 32} 33 34// Put stores value under key, dropping the oldest entry when full. 35func (c *Products) Put(key string, value any) { 36 if el, ok := c.items[key]; ok { 37 el.Value.(*item).value = value 38 c.order.MoveToFront(el) 39 return 40 } 41 el := c.order.PushFront(&item{key: key, value: value}) 42 c.items[key] = el 43 if c.order.Len() > c.size { 44 last := c.order.Back() 45 c.order.Remove(last) 46 e := last.Value.(*item) 47 delete(c.items, e.key) 48 if c.evict != nil { 49 c.evict(e.key, e.value) 50 } 51 } 52}
Their code
6package mplcache 7 8import "container/list" 9 10type entry struct { 11 key string 12 value any 13} 14 15// LRU keeps at most Size entries and drops the least recently used one. 16type LRU struct { 17 size int 18 order *list.List 19 items map[string]*list.Element 20 evict func(key string, value any) 21} 22 23// New returns an empty cache for size entries. evict, if set, is called 24// for every entry the cache drops. 25func New(size int, evict func(key string, value any)) *LRU { 26 return &LRU{size: size, order: list.New(), items: make(map[string]*list.Element), evict: evict} 27} 28 29// Get returns the value for key and marks it as recently used. 30func (c *LRU) Get(key string) (any, bool) { 31 el, ok := c.items[key] 32 if !ok { 33 return nil, false 34 } 35 c.order.MoveToFront(el) 36 return el.Value.(*entry).value, true 37} 38 39// Put stores value under key, dropping the oldest entry when the cache is full. 40func (c *LRU) Put(key string, value any) { 41 if el, ok := c.items[key]; ok { 42 el.Value.(*entry).value = value 43 c.order.MoveToFront(el) 44 return 45 } 46 el := c.order.PushFront(&entry{key: key, value: value}) 47 c.items[key] = el 48 if c.order.Len() > c.size { 49 last := c.order.Back() 50 c.order.Remove(last) 51 e := last.Value.(*entry) 52 delete(c.items, e.key) 53 if c.evict != nil { 54 c.evict(e.key, e.value) 55 } 56 } 57}
Keep its copyright line and the MIT licence text with your copy, for example in a third-party notices file.
Your code
2package csvio 3 4import ( 5 "errors" 6 "strings" 7) 8 9// ErrQuote is returned for a field with an unterminated quote. 10var ErrQuote = errors.New("fastcsv: unterminated quote") 11 12// SplitRecord splits one line into fields. Fields may be quoted with double 13// quotes; a doubled quote inside a quoted field stands for one quote. 14func SplitRecord(line string, sep rune) ([]string, error) { 15 var fields []string 16 var field strings.Builder 17 inQuotes := false 18 runes := []rune(line) 19 for i := 0; i < len(runes); i++ { 20 r := runes[i] 21 switch { 22 case inQuotes && r == '"': 23 if i+1 < len(runes) && runes[i+1] == '"' { 24 field.WriteRune('"') 25 i++ 26 } else { 27 inQuotes = false 28 } 29 case inQuotes: 30 field.WriteRune(r) 31 case r == '"' && field.Len() == 0: 32 inQuotes = true 33 case r == sep: 34 fields = append(fields, field.String()) 35 field.Reset() 36 default: 37 field.WriteRune(r) 38 } 39 } 40 if inQuotes { 41 return nil, ErrQuote 42 } 43 fields = append(fields, field.String()) 44 return fields, nil 45}
Their code
2package fastcsv 3 4import ( 5 "errors" 6 "strings" 7) 8 9// ErrQuote is returned for a field with an unterminated quote. 10var ErrQuote = errors.New("fastcsv: unterminated quote") 11 12// SplitRecord splits one line into fields. Fields may be quoted with double 13// quotes; a doubled quote inside a quoted field stands for one quote. 14func SplitRecord(line string, sep rune) ([]string, error) { 15 var fields []string 16 var field strings.Builder 17 inQuotes := false 18 runes := []rune(line) 19 for i := 0; i < len(runes); i++ { 20 r := runes[i] 21 switch { 22 case inQuotes && r == '"': 23 if i+1 < len(runes) && runes[i+1] == '"' { 24 field.WriteRune('"') 25 i++ 26 } else { 27 inQuotes = false 28 } 29 case inQuotes: 30 field.WriteRune(r) 31 case r == '"' && field.Len() == 0: 32 inQuotes = true 33 case r == sep: 34 fields = append(fields, field.String()) 35 field.Reset() 36 default: 37 field.WriteRune(r) 38 } 39 } 40 if inQuotes { 41 return nil, ErrQuote 42 } 43 fields = append(fields, field.String()) 44 return fields, nil 45}
Keep its copyright line and the MIT licence text with your copy, for example in a third-party notices file.
Your code
1"""Print the catalog as readable JSON.""" 2 3 4def to_text(obj, width=2, depth=0): 5 """Format obj as indented JSON text.""" 6 pad = " " * (width * depth) 7 inner = " " * (width * (depth + 1)) 8 if isinstance(obj, dict): 9 if not obj: 10 return "{}" 11 parts = [] 12 for name in sorted(obj): 13 text = to_text(obj[name], width, depth + 1) 14 parts.append('%s"%s": %s' % (inner, quote(str(name)), text)) 15 return "{\n" + ",\n".join(parts) + "\n" + pad + "}" 16 if isinstance(obj, (list, tuple)): 17 if not obj: 18 return "[]" 19 parts = [inner + to_text(v, width, depth + 1) for v in obj] 20 return "[\n" + ",\n".join(parts) + "\n" + pad + "]" 21 if obj is None: 22 return "null" 23 if obj is True or obj is False: 24 return "true" if obj else "false" 25 if isinstance(obj, (int, float)): 26 return repr(obj) 27 return '"%s"' % quote(str(obj)) 28 29 30def quote(text): 31 """Escape a string for JSON.""" 32 return text.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
Their code
1"""A very small JSON pretty printer.""" 2 3 4def pretty(value, indent=2, level=0): 5 """Format value as indented JSON text.""" 6 pad = " " * (indent * level) 7 inner = " " * (indent * (level + 1)) 8 if isinstance(value, dict): 9 if not value: 10 return "{}" 11 parts = [] 12 for key in sorted(value): 13 text = pretty(value[key], indent, level + 1) 14 parts.append('%s"%s": %s' % (inner, escape(str(key)), text)) 15 return "{\n" + ",\n".join(parts) + "\n" + pad + "}" 16 if isinstance(value, (list, tuple)): 17 if not value: 18 return "[]" 19 parts = [inner + pretty(v, indent, level + 1) for v in value] 20 return "[\n" + ",\n".join(parts) + "\n" + pad + "]" 21 if value is None: 22 return "null" 23 if value is True or value is False: 24 return "true" if value else "false" 25 if isinstance(value, (int, float)): 26 return repr(value) 27 return '"%s"' % escape(str(value)) 28 29 30def escape(text): 31 """Escape a string for JSON.""" 32 return text.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
Keep its copyright line and the ISC licence text with your copy, for example in a third-party notices file.
Your code
1'use strict'; 2 3// Pads str on the left with ch until it is len characters long. 4function leftPad(str, len, ch) { 5 str = String(str); 6 if (ch === undefined || ch === null || ch === '') { 7 ch = ' '; 8 } else { 9 ch = String(ch); 10 } 11 let pad = len - str.length; 12 if (pad <= 0) { 13 return str; 14 } 15 let out = ''; 16 while (pad > 0) { 17 if (pad & 1) { 18 out += ch; 19 } 20 pad >>= 1; 21 if (pad) { 22 ch += ch; 23 } 24 } 25 return out + str; 26} 27 28module.exports = leftPad;
Their code
1'use strict'; 2 3// Pads str on the left with ch until it is len characters long. 4function leftPad(str, len, ch) { 5 str = String(str); 6 if (ch === undefined || ch === null || ch === '') { 7 ch = ' '; 8 } else { 9 ch = String(ch); 10 } 11 let pad = len - str.length; 12 if (pad <= 0) { 13 return str; 14 } 15 let out = ''; 16 while (pad > 0) { 17 if (pad & 1) { 18 out += ch; 19 } 20 pad >>= 1; 21 if (pad) { 22 ch += ch; 23 } 24 } 25 return out + str; 26} 27 28module.exports = leftPad;
Keep its copyright line and the BSD-3-Clause licence text with your copy, for example in a third-party notices file.
Your code
3function debounce(callback, delay, leading) { 4 let handle = null; 5 let pending = null; 6 function fire() { 7 handle = null; 8 if (!leading && pending) { 9 callback.apply(null, pending); 10 pending = null; 11 } 12 } 13 return function wrapped(...params) { 14 const runNow = leading && handle === null; 15 pending = params; 16 if (handle !== null) { 17 clearTimeout(handle); 18 } 19 handle = setTimeout(fire, delay); 20 if (runNow) { 21 callback.apply(null, params); 22 pending = null; 23 } 24 }; 25}
Their code
6function debounce(fn, wait, immediate) { 7 let timer = null; 8 let lastArgs = null; 9 function later() { 10 timer = null; 11 if (!immediate && lastArgs) { 12 fn.apply(null, lastArgs); 13 lastArgs = null; 14 } 15 } 16 return function debounced(...args) { 17 const callNow = immediate && timer === null; 18 lastArgs = args; 19 if (timer !== null) { 20 clearTimeout(timer); 21 } 22 timer = setTimeout(later, wait); 23 if (callNow) { 24 fn.apply(null, args); 25 lastArgs = null; 26 } 27 }; 28}
Credited in the project's notices. Keep its copyright line, the Apache-2.0 licence text and any NOTICE text the project ships, and mark files you changed.
Your code
13func backoff(n int, base, max time.Duration, jitter float64, rnd func() float64) time.Duration { 14 d := base 15 for i := 0; i < n && d < max; i++ { 16 d *= 2 17 } 18 if d > max { 19 d = max 20 } 21 if jitter > 0 { 22 spread := float64(d) * jitter 23 d = time.Duration(float64(d) - spread + 2*spread*rnd()) 24 } 25 return d 26} 27 28// retry calls fn until it succeeds, the context ends, or attempts run out. 29func retry(ctx context.Context, attempts int, base, max time.Duration, fn func() error) error { 30 var err error 31 for n := 0; n < attempts; n++ { 32 if err = fn(); err == nil { 33 return nil 34 } 35 if errors.Is(err, context.Canceled) { 36 return err 37 } 38 wait := backoff(n, base, max, 0.2, rand.Float64) 39 select { 40 case <-ctx.Done(): 41 return ctx.Err() 42 case <-time.After(wait): 43 } 44 } 45 return fmt.Errorf("shopfront: service unavailable after %d attempts: %w", attempts, err) 46}
Their code
22func Backoff(n int, base, max time.Duration, jitter float64, rnd func() float64) time.Duration { 23 d := base 24 for i := 0; i < n && d < max; i++ { 25 d *= 2 26 } 27 if d > max { 28 d = max 29 } 30 if jitter > 0 { 31 spread := float64(d) * jitter 32 d = time.Duration(float64(d) - spread + 2*spread*rnd()) 33 } 34 return d 35} 36 37// Retryable reports whether an error is worth another attempt. 38func Retryable(err error) bool { 39 if err == nil { 40 return false 41 } 42 if errors.Is(err, ErrPermanent) || errors.Is(err, context.Canceled) { 43 return false 44 } 45 var t interface{ Temporary() bool } 46 if errors.As(err, &t) { 47 return t.Temporary() 48 } 49 return true 50} 51 52// Do calls fn until it succeeds, the context ends, or attempts run out. 53func Do(ctx context.Context, attempts int, base, max time.Duration, fn func() error) error { 54 var err error 55 for n := 0; n < attempts; n++ { 56 if err = fn(); err == nil { 57 return nil 58 } 59 if !Retryable(err) { 60 return err 61 } 62 wait := Backoff(n, base, max, 0.2, rand.Float64) 63 select { 64 case <-ctx.Done(): 65 return ctx.Err() 66 case <-time.After(wait): 67 } 68 } 69 return fmt.Errorf("retrykit: gave up after %d attempts: %w", attempts, err) 70}