feat(qrApi): Got newest version of piglig/go-qr lib
Build and Push Docker image / build-and-push (push) Successful in 2m32s
Details
Build and Push Docker image / build-and-push (push) Successful in 2m32s
Details
This commit is contained in:
parent
99d13843b0
commit
d3658f58f2
1
go.mod
1
go.mod
|
@ -58,6 +58,7 @@ require (
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
|
github.com/piglig/go-qr v0.2.4 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/spf13/cast v1.6.0 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/cobra v1.8.0 // indirect
|
github.com/spf13/cobra v1.8.0 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -271,6 +271,8 @@ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQ
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
|
github.com/piglig/go-qr v0.2.4 h1:G/fY3/Oq0NI1oc0lEhBv75QXUtIW/FmcL9l8D1jIo1M=
|
||||||
|
github.com/piglig/go-qr v0.2.4/go.mod h1:funyXL4IdgMPcbICoVm1XweMtZy7Px3kyITTENkmA5w=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
package goqr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BitSet defines an interface that allows manipulation of a bitset.
|
|
||||||
type BitSet interface {
|
|
||||||
getBit(i int) bool
|
|
||||||
set(i int, value bool)
|
|
||||||
len() int
|
|
||||||
}
|
|
||||||
|
|
||||||
type BitBuffer []bool
|
|
||||||
|
|
||||||
// len returns the length of the BitBuffer.
|
|
||||||
func (b *BitBuffer) len() int {
|
|
||||||
return len(*b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// set sets the bit at position i in the BitBuffer to value.
|
|
||||||
func (b *BitBuffer) set(i int, value bool) {
|
|
||||||
if i >= len(*b) {
|
|
||||||
b.grow(1 + i) // If index is beyond current length, grow buffer.
|
|
||||||
}
|
|
||||||
(*b)[i] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// getBit returns the bit at position i in the BitBuffer.
|
|
||||||
func (b *BitBuffer) getBit(i int) bool {
|
|
||||||
if i >= len(*b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return (*b)[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// grow increases the size of the BitBuffer.
|
|
||||||
func (b *BitBuffer) grow(size int) {
|
|
||||||
res := make(BitBuffer, size)
|
|
||||||
copy(res, *b)
|
|
||||||
*b = res
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendBits appends val as a binary number of length bits to the end of the BitBuffer.
|
|
||||||
func (b *BitBuffer) appendBits(val, length int) error {
|
|
||||||
if length < 0 || length > 31 || (val>>uint(length)) != 0 {
|
|
||||||
return fmt.Errorf("value out of range")
|
|
||||||
}
|
|
||||||
if math.MaxInt32-b.len() < length {
|
|
||||||
return fmt.Errorf("maximum length reached")
|
|
||||||
}
|
|
||||||
for i := length - 1; i >= 0; i-- {
|
|
||||||
b.set(b.len(), getBit(val, i))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendData appends another BitBuffer to this BitBuffer.
|
|
||||||
func (b *BitBuffer) appendData(other *BitBuffer) error {
|
|
||||||
if other == nil {
|
|
||||||
return fmt.Errorf("BitBuffer is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
if math.MaxInt32-b.len() < other.len() {
|
|
||||||
return fmt.Errorf("maximum length reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < other.len(); i++ {
|
|
||||||
bit := other.getBit(i)
|
|
||||||
b.set(b.len(), bit)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// clone creates a copy of the BitBuffer.
|
|
||||||
func (b *BitBuffer) clone() *BitBuffer {
|
|
||||||
clone := make(BitBuffer, len(*b))
|
|
||||||
copy(clone, *b)
|
|
||||||
return &clone
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package goqr
|
|
||||||
|
|
||||||
type DataTooLongException struct {
|
|
||||||
Msg string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DataTooLongException) Error() string {
|
|
||||||
return d.Msg
|
|
||||||
}
|
|
1019
goqr/qr_code.go
1019
goqr/qr_code.go
File diff suppressed because it is too large
Load Diff
|
@ -1,299 +0,0 @@
|
||||||
package goqr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"math"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mode is the representation of the mode of a QR code character.
|
|
||||||
type Mode struct {
|
|
||||||
modeBits int // 4-bit mode indicator used in QR Code's data encoding
|
|
||||||
numBitsCharCount []int // number of bits used for character count indicator for different versions
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMode creates a new Mode with a given mode indicator and character count bits
|
|
||||||
func newMode(mode int, ccbits ...int) Mode {
|
|
||||||
return Mode{
|
|
||||||
modeBits: mode,
|
|
||||||
numBitsCharCount: ccbits,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// numCharCountBits returns the number of character count bits
|
|
||||||
// for a specific QR code version.
|
|
||||||
func (m Mode) numCharCountBits(ver int) int {
|
|
||||||
return m.numBitsCharCount[(ver+7)/17]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Predefined Mode values as defined by the QR Code standard.
|
|
||||||
var (
|
|
||||||
// Numeric mode is typically used for decimal digits (0 through 9).
|
|
||||||
Numeric = newMode(0x1, 10, 12, 14)
|
|
||||||
|
|
||||||
// Alphanumeric mode includes digits 0-9, uppercase letters A-Z and nine special characters.
|
|
||||||
Alphanumeric = newMode(0x2, 9, 11, 13)
|
|
||||||
|
|
||||||
// Byte mode can encode binary/byte data(default: ISO-8859-1)
|
|
||||||
Byte = newMode(0x4, 8, 16, 16) // Byte mode: binary/byte data (default: ISO-8859-1)
|
|
||||||
|
|
||||||
// Kanji mode is used for encoding Japanese Kanji characters.
|
|
||||||
Kanji = newMode(0x8, 8, 10, 12)
|
|
||||||
|
|
||||||
// Eci mode is designed for providing a method of extending features and functions
|
|
||||||
// in bar code symbols beyond those envisioned by the original standard.
|
|
||||||
Eci = newMode(0x7, 0, 0, 0)
|
|
||||||
)
|
|
||||||
|
|
||||||
// getModeBits function to return the bits representing a particular mode
|
|
||||||
func (m Mode) getModeBits() int {
|
|
||||||
return m.modeBits
|
|
||||||
}
|
|
||||||
|
|
||||||
// isNumeric checks if the mode is Numeric.
|
|
||||||
func (m Mode) isNumeric() bool {
|
|
||||||
return m.modeBits == Numeric.getModeBits()
|
|
||||||
}
|
|
||||||
|
|
||||||
// isAlphanumeric checks if the mode is Alphanumeric.
|
|
||||||
func (m Mode) isAlphanumeric() bool {
|
|
||||||
return m.modeBits == Alphanumeric.getModeBits()
|
|
||||||
}
|
|
||||||
|
|
||||||
// isByte checks if the mode is Byte.
|
|
||||||
func (m Mode) isByte() bool {
|
|
||||||
return m.modeBits == Byte.getModeBits()
|
|
||||||
}
|
|
||||||
|
|
||||||
// isKanji checks if the mode is Kanji.
|
|
||||||
func (m Mode) isKanji() bool {
|
|
||||||
return m.modeBits == Kanji.getModeBits()
|
|
||||||
}
|
|
||||||
|
|
||||||
// isEci checks if the mode is ECI.
|
|
||||||
func (m Mode) isEci() bool {
|
|
||||||
return m.modeBits == Eci.getModeBits()
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// numericRegex is a regular expression that matches strings consisting only of numbers (0-9).
|
|
||||||
numericRegex = regexp.MustCompile(`^\d+$`)
|
|
||||||
|
|
||||||
// alphanumericRegex is a regular expression that matches strings
|
|
||||||
// consisting only of numeric characters, uppercase alphabets, and certain special characters ($%*+-./:).
|
|
||||||
alphanumericRegex = regexp.MustCompile(`^[0-9A-Z $%*+\-.\/:]*$`)
|
|
||||||
|
|
||||||
// alphanumericCharset is a string listing all the characters that can be used in an alphanumeric string in QR codes.
|
|
||||||
alphanumericCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
|
|
||||||
)
|
|
||||||
|
|
||||||
// QrSegment is the representation of a segment of a QR code.
|
|
||||||
type QrSegment struct {
|
|
||||||
mode Mode // The mode of the QR segment (e.g., Numeric, Alphanumeric, etc.)
|
|
||||||
numChars int // Number of characters in the segment
|
|
||||||
data *BitBuffer // The actual binary data represented by this QR segment
|
|
||||||
}
|
|
||||||
|
|
||||||
// newQrSegment function creates a new QR segment with the given mode, number of characters, and data.
|
|
||||||
func newQrSegment(mode Mode, numCh int, data *BitBuffer) (*QrSegment, error) {
|
|
||||||
if numCh < 0 {
|
|
||||||
return nil, errors.New("invalid value")
|
|
||||||
}
|
|
||||||
return &QrSegment{
|
|
||||||
mode: mode,
|
|
||||||
numChars: numCh,
|
|
||||||
data: data.clone(), // Use a cloned copy of the data to prevent modifications
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getData method clones and returns the BitBuffer data of the QR segment.
|
|
||||||
func (q *QrSegment) getData() *BitBuffer {
|
|
||||||
return q.data.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeBytes converts a byte slice into a QR segment in Byte mode.
|
|
||||||
// It returns an error if the input data is nil.
|
|
||||||
func MakeBytes(data []byte) (*QrSegment, error) {
|
|
||||||
if data == nil {
|
|
||||||
return nil, errors.New("data is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
bb := &BitBuffer{}
|
|
||||||
for _, b := range data {
|
|
||||||
err := bb.appendBits(int(b&0xFF), 8) // Append 8 bits at once to the bit buffer
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newQrSegment(Byte, len(data), bb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeNumeric converts a string of digits into a QR code segment in Numeric mode
|
|
||||||
// It returns an error if the string contains non-numeric characters.
|
|
||||||
func MakeNumeric(digits string) (*QrSegment, error) {
|
|
||||||
if !isNumeric(digits) {
|
|
||||||
return nil, errors.New("string contains non-numeric characters")
|
|
||||||
}
|
|
||||||
|
|
||||||
bb := &BitBuffer{}
|
|
||||||
for i := 0; i < len(digits); {
|
|
||||||
n := min(len(digits)-i, 3) // find the length of the current chunk (up to 3 digits)
|
|
||||||
num, _ := strconv.Atoi(digits[i : i+n]) // convert the current chunk to an integer
|
|
||||||
err := bb.appendBits(num, n*3+1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
i += n // advance to the next chunk
|
|
||||||
}
|
|
||||||
|
|
||||||
return newQrSegment(Numeric, len(digits), bb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isNumeric function takes a string as input and returns a boolean indicating whether the string is numeric.
|
|
||||||
// It uses the MatchString method on the numericRegex to check the input string.
|
|
||||||
func isNumeric(numb string) bool {
|
|
||||||
return numericRegex.MatchString(numb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isAlphanumeric function takes a string as input and returns a boolean indicating whether the string is alphanumeric.
|
|
||||||
// It uses the MatchString method on the alphanumericRegex to check the input string.
|
|
||||||
func isAlphanumeric(text string) bool {
|
|
||||||
return alphanumericRegex.MatchString(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func min(a, b int) int {
|
|
||||||
if a < b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(a, b int) int {
|
|
||||||
if a < b {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func abs(x int) int {
|
|
||||||
if x < 0 {
|
|
||||||
return -x
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeAlphanumeric converts a string into a QR code segment in Alphanumeric mode
|
|
||||||
// It returns an error if the string contains non-alphanumeric characters.
|
|
||||||
func MakeAlphanumeric(text string) (*QrSegment, error) {
|
|
||||||
if !isAlphanumeric(text) {
|
|
||||||
return nil, errors.New("string contains unencodable characters in alphanumeric mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
bb := &BitBuffer{}
|
|
||||||
i := 0
|
|
||||||
for ; i <= len(text)-2; i += 2 {
|
|
||||||
// Process each pair of characters in text.
|
|
||||||
temp := strings.IndexByte(alphanumericCharset, text[i]) * 45
|
|
||||||
temp += strings.IndexByte(alphanumericCharset, text[i+1])
|
|
||||||
err := bb.appendBits(temp, 11)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if i < len(text) {
|
|
||||||
err := bb.appendBits(strings.IndexByte(alphanumericCharset, text[i]), 6)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newQrSegment(Alphanumeric, len(text), bb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeSegments converts data into QR segments based on the mode of text (Numeric, Alphanumeric or Byte, etc).
|
|
||||||
func MakeSegments(text string) ([]*QrSegment, error) {
|
|
||||||
res := make([]*QrSegment, 0)
|
|
||||||
if text == "" {
|
|
||||||
} else if isNumeric(text) {
|
|
||||||
seg, err := MakeNumeric(text)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res = append(res, seg)
|
|
||||||
} else if isAlphanumeric(text) {
|
|
||||||
seg, err := MakeAlphanumeric(text)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res = append(res, seg)
|
|
||||||
} else {
|
|
||||||
seg, err := MakeBytes([]byte(text))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res = append(res, seg)
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeEci converts an integer into a QR code segment in Eci mode
|
|
||||||
// It returns an error if the integer value is out of range.
|
|
||||||
func MakeEci(val int) (*QrSegment, error) {
|
|
||||||
bb := &BitBuffer{}
|
|
||||||
if val < 0 {
|
|
||||||
return nil, errors.New("ECI assignment value out of range")
|
|
||||||
} else if val < (1 << 7) {
|
|
||||||
err := bb.appendBits(val, 8)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if val < (1 << 14) {
|
|
||||||
err := bb.appendBits(0b10, 2)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bb.appendBits(val, 14)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if val < 1e6 {
|
|
||||||
err := bb.appendBits(0b110, 3)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bb.appendBits(val, 21)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("ECI assignment value out of range")
|
|
||||||
}
|
|
||||||
return newQrSegment(Eci, 0, bb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTotalBits calculates and returns the total number of bits required to encode the segments at the specified QR version.
|
|
||||||
// It returns -1 if the number of characters exceeds the maximum capacity.
|
|
||||||
func getTotalBits(segs []*QrSegment, ver int) int {
|
|
||||||
var res int64
|
|
||||||
for _, seg := range segs {
|
|
||||||
if seg == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ccbits := seg.mode.numCharCountBits(ver)
|
|
||||||
if seg.numChars >= (1 << ccbits) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
res += int64(4 + ccbits + seg.data.len())
|
|
||||||
if res > math.MaxInt32 {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return int(res)
|
|
||||||
}
|
|
|
@ -1,380 +0,0 @@
|
||||||
package goqr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"unicode/utf16"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MakeSegmentsOptimally takes a string and error correction level, and attempts to
|
|
||||||
// make QR segments in the most efficient way possible. It validates the version
|
|
||||||
// range and converts the input text into code points. Then, it loops through
|
|
||||||
// each version, attempting to make segments until the data fits within the
|
|
||||||
// capacity of the version. Returns an array of pointers to QrSegment or an error.
|
|
||||||
func MakeSegmentsOptimally(text string, ecl Ecc, minVersion, maxVersion int) ([]*QrSegment, error) {
|
|
||||||
if !isValidVersion(minVersion, maxVersion) {
|
|
||||||
return nil, errors.New("invalid value")
|
|
||||||
}
|
|
||||||
|
|
||||||
codePoints, err := toCodePoints(text)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for version := minVersion; ; version++ {
|
|
||||||
if version == minVersion || version == 10 || version == 27 {
|
|
||||||
segs, err := makeSegmentsOptimallyWithVersion(codePoints, version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dataCapacityBits := getNumDataCodewords(version, ecl) * 8
|
|
||||||
dataUsedBits := getTotalBits(segs, version)
|
|
||||||
if dataUsedBits != -1 && dataUsedBits <= dataCapacityBits {
|
|
||||||
return segs, nil
|
|
||||||
}
|
|
||||||
if version >= maxVersion {
|
|
||||||
msg := "segment too long"
|
|
||||||
if dataUsedBits != -1 {
|
|
||||||
msg = fmt.Sprintf("data length = %d bits, max capacity = %d bits", dataUsedBits, dataCapacityBits)
|
|
||||||
}
|
|
||||||
return nil, &DataTooLongException{Msg: msg}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeSegmentsOptimallyWithVersion takes code points and a version number,
|
|
||||||
// computes the character modes suitable for that version, and then splits the
|
|
||||||
// code points into segments accordingly. Returns an array of pointers to
|
|
||||||
// QrSegment or an error.
|
|
||||||
func makeSegmentsOptimallyWithVersion(codePoints []int, version int) ([]*QrSegment, error) {
|
|
||||||
charModes, err := computeCharacterModes(codePoints, version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return splitIntoSegments(codePoints, charModes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// toCodePoints returns a new slice of Unicode code points (effectively
|
|
||||||
// UTF-32 / UCS-4) representing the given UTF-16 string.
|
|
||||||
func toCodePoints(s string) ([]int, error) {
|
|
||||||
runes := []rune(s)
|
|
||||||
codePoints := make([]int, len(runes))
|
|
||||||
for i, r := range runes {
|
|
||||||
if utf16.IsSurrogate(r) {
|
|
||||||
return nil, errors.New("invalid UTF-16 string")
|
|
||||||
}
|
|
||||||
codePoints[i] = int(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
return codePoints, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// countUtf8Bytes counts the number of bytes required to represent a Unicode code point in UTF-8.
|
|
||||||
func countUtf8Bytes(cp int) (int, error) {
|
|
||||||
if cp < 0 {
|
|
||||||
return 0, errors.New("invalid code point")
|
|
||||||
} else if cp < 0x80 {
|
|
||||||
return 1, nil
|
|
||||||
} else if cp < 0x800 {
|
|
||||||
return 2, nil
|
|
||||||
} else if cp < 0x10000 {
|
|
||||||
return 3, nil
|
|
||||||
} else if cp < 0x110000 {
|
|
||||||
return 4, nil
|
|
||||||
} else {
|
|
||||||
return 0, errors.New("invalid code point")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// computeCharacterModes determines the optimal encoding mode for each character in the input string.
|
|
||||||
func computeCharacterModes(codePoints []int, version int) ([]Mode, error) {
|
|
||||||
if len(codePoints) > 7089 {
|
|
||||||
return nil, errors.New("string too long")
|
|
||||||
}
|
|
||||||
modeTypes := []Mode{Byte, Alphanumeric, Numeric, Kanji}
|
|
||||||
numModes := len(modeTypes)
|
|
||||||
|
|
||||||
headCosts := make([]int, numModes)
|
|
||||||
charModes := make([][]Mode, len(codePoints))
|
|
||||||
for i := 0; i < numModes; i++ {
|
|
||||||
headCosts[i] = (4 + modeTypes[i].numCharCountBits(version)) * 6
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range charModes {
|
|
||||||
charModes[i] = make([]Mode, numModes)
|
|
||||||
}
|
|
||||||
|
|
||||||
prevCosts := make([]int, numModes)
|
|
||||||
copy(prevCosts, headCosts)
|
|
||||||
|
|
||||||
// Determine the mode type for each character based on cost calculation
|
|
||||||
for i := 0; i < len(codePoints); i++ {
|
|
||||||
c := codePoints[i]
|
|
||||||
curCosts := make([]int, numModes)
|
|
||||||
{
|
|
||||||
count, err := countUtf8Bytes(c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
curCosts[0] = prevCosts[0] + count*8*6
|
|
||||||
charModes[i][0] = modeTypes[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if isAlphanumeric(string(rune(c))) {
|
|
||||||
curCosts[1] = prevCosts[1] + 33
|
|
||||||
charModes[i][1] = modeTypes[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if isNumeric(string(rune(c))) {
|
|
||||||
curCosts[2] = prevCosts[2] + 20
|
|
||||||
charModes[i][2] = modeTypes[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
if isKanji(c) {
|
|
||||||
curCosts[3] = prevCosts[3] + 78
|
|
||||||
charModes[i][3] = modeTypes[3]
|
|
||||||
}
|
|
||||||
|
|
||||||
for j := 0; j < numModes; j++ {
|
|
||||||
for k := 0; k < numModes; k++ {
|
|
||||||
newCost := (curCosts[k]+5)/6*6 + headCosts[j]
|
|
||||||
if charModes[i][k].getModeBits() != 0 && (charModes[i][j].getModeBits() == 0 || newCost < curCosts[j]) {
|
|
||||||
curCosts[j] = newCost
|
|
||||||
charModes[i][j] = modeTypes[k]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prevCosts = curCosts
|
|
||||||
}
|
|
||||||
|
|
||||||
curMode := Mode{}
|
|
||||||
for i, minCost := 0, 0; i < numModes; i++ {
|
|
||||||
if curMode.getModeBits() == 0 || prevCosts[i] < minCost {
|
|
||||||
minCost = prevCosts[i]
|
|
||||||
curMode = modeTypes[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]Mode, len(charModes))
|
|
||||||
for i := len(res) - 1; i >= 0; i-- {
|
|
||||||
for j := 0; j < numModes; j++ {
|
|
||||||
if reflect.DeepEqual(modeTypes[j], curMode) {
|
|
||||||
curMode = charModes[i][j]
|
|
||||||
res[i] = curMode
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// splitIntoSegments is used to splits the input into multiple QR segments according to the given modes.
|
|
||||||
// Each change in mode results in a new segment being created.
|
|
||||||
func splitIntoSegments(codePoints []int, charModes []Mode) ([]*QrSegment, error) {
|
|
||||||
res := make([]*QrSegment, 0)
|
|
||||||
curMode := charModes[0]
|
|
||||||
start := 0
|
|
||||||
for i := 1; ; i++ {
|
|
||||||
if i < len(codePoints) && reflect.DeepEqual(charModes[i], curMode) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
runes := make([]rune, i-start)
|
|
||||||
for j, cp := range codePoints[start:i] {
|
|
||||||
runes[j] = rune(cp)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := string(runes)
|
|
||||||
|
|
||||||
// Create a QR segment based on the current mode
|
|
||||||
if curMode.isByte() {
|
|
||||||
qs, err := MakeBytes([]byte(s))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res = append(res, qs)
|
|
||||||
} else if curMode.isNumeric() {
|
|
||||||
qs, err := MakeNumeric(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res = append(res, qs)
|
|
||||||
} else if curMode.isAlphanumeric() {
|
|
||||||
qs, err := MakeAlphanumeric(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res = append(res, qs)
|
|
||||||
} else if curMode.isKanji() {
|
|
||||||
qs, err := MakeKanji(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res = append(res, qs)
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("invalid mode")
|
|
||||||
}
|
|
||||||
if i >= len(codePoints) {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
curMode = charModes[i]
|
|
||||||
start = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeKanji converts a string into a QR code segment in Kanji mode
|
|
||||||
// It returns an error if the string contains non-kanji characters.
|
|
||||||
func MakeKanji(text string) (*QrSegment, error) {
|
|
||||||
bb := &BitBuffer{}
|
|
||||||
runes := []rune(text)
|
|
||||||
for _, c := range text {
|
|
||||||
if !isKanji(int(c)) {
|
|
||||||
return nil, errors.New("string contains non-kanji-mode characters")
|
|
||||||
}
|
|
||||||
val := unicdeToQRKanji[c]
|
|
||||||
err := bb.appendBits(val, 13)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newQrSegment(Kanji, len(runes), bb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isKanji function takes a integer as input and returns a boolean indicating whether the integer is Kanji.
|
|
||||||
func isKanji(c int) bool {
|
|
||||||
return c < len(unicdeToQRKanji) && unicdeToQRKanji[c] != -1 && c >= 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const packedQRKanjiToUnicode = "MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZA" +
|
|
||||||
"ALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA///////////////////" +
|
|
||||||
"//////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h" +
|
|
||||||
"/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBN" +
|
|
||||||
"ME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////" +
|
|
||||||
"////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDh" +
|
|
||||||
"MOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+" +
|
|
||||||
"A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQm" +
|
|
||||||
"BCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQ" +
|
|
||||||
"JRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"/////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32t" +
|
|
||||||
"fe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYg" +
|
|
||||||
"ZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2" +
|
|
||||||
"cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5" +
|
|
||||||
"////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLs" +
|
|
||||||
"bTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CE" +
|
|
||||||
"lFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKg" +
|
|
||||||
"dZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/" +
|
|
||||||
"U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6" +
|
|
||||||
"UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo" +
|
|
||||||
"//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6r" +
|
|
||||||
"XydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOn" +
|
|
||||||
"ZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtk" +
|
|
||||||
"mANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiV" +
|
|
||||||
"nfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/X" +
|
|
||||||
"YB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6luf" +
|
|
||||||
"hQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/S" +
|
|
||||||
"ge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZ" +
|
|
||||||
"WXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJac" +
|
|
||||||
"l5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066" +
|
|
||||||
"TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bb" +
|
|
||||||
"fL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6" +
|
|
||||||
"ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333P" +
|
|
||||||
"fZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7e" +
|
|
||||||
"gM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bj" +
|
|
||||||
"WMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0" +
|
|
||||||
"gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oC" +
|
|
||||||
"iuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhY" +
|
|
||||||
"WVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLr" +
|
|
||||||
"W8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/D" +
|
|
||||||
"fQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGro" +
|
|
||||||
"XmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/" +
|
|
||||||
"l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16c" +
|
|
||||||
"YBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7" +
|
|
||||||
"WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851s" +
|
|
||||||
"Tk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04H" +
|
|
||||||
"YWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5f" +
|
|
||||||
"UbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+K" +
|
|
||||||
"gACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHM" +
|
|
||||||
"W+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3v" +
|
|
||||||
"lzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"/////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/l" +
|
|
||||||
"UBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGT" +
|
|
||||||
"UZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQ" +
|
|
||||||
"Uw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////" +
|
|
||||||
"VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaP" +
|
|
||||||
"VqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4" +
|
|
||||||
"WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrj" +
|
|
||||||
"Wtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yr" +
|
|
||||||
"XLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/" +
|
|
||||||
"XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQ" +
|
|
||||||
"YClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FY" +
|
|
||||||
"YVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KU" +
|
|
||||||
"Ytdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTH" +
|
|
||||||
"ZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2Zo" +
|
|
||||||
"Zl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGge" +
|
|
||||||
"aEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammy" +
|
|
||||||
"aa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7" +
|
|
||||||
"awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzX" +
|
|
||||||
"bMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7J" +
|
|
||||||
"brdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3Aw" +
|
|
||||||
"cD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKy" +
|
|
||||||
"csNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTy" +
|
|
||||||
"dPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYw" +
|
|
||||||
"djt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7" +
|
|
||||||
"d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXog" +
|
|
||||||
"eh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuc" +
|
|
||||||
"e5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G" +
|
|
||||||
"////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5a" +
|
|
||||||
"fnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAh" +
|
|
||||||
"gCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHC" +
|
|
||||||
"gbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMv" +
|
|
||||||
"gyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UY" +
|
|
||||||
"hSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs" +
|
|
||||||
"//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZ" +
|
|
||||||
"iF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9" +
|
|
||||||
"ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tf" +
|
|
||||||
"i2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3b" +
|
|
||||||
"jcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485" +
|
|
||||||
"j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEy" +
|
|
||||||
"kTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNW" +
|
|
||||||
"k7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYu" +
|
|
||||||
"li+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJem" +
|
|
||||||
"l6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnY" +
|
|
||||||
"mdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uD" +
|
|
||||||
"m5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1k" +
|
|
||||||
"nVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+" +
|
|
||||||
"n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
|
|
||||||
"/////////////////////////////////////////////w=="
|
|
||||||
|
|
||||||
var unicdeToQRKanji [1 << 16]int
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
for i := range unicdeToQRKanji {
|
|
||||||
unicdeToQRKanji[i] = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes, _ := base64.StdEncoding.DecodeString(packedQRKanjiToUnicode)
|
|
||||||
for i := 0; i < len(bytes); i += 2 {
|
|
||||||
c := int(bytes[i]&0xFF)<<8 | int(bytes[i+1]&0xFF)
|
|
||||||
if c == 0xFFFF {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
unicdeToQRKanji[c] = i / 2
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,9 +2,9 @@ package qrApi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
goqr "git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/goqr"
|
|
||||||
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger"
|
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger"
|
||||||
"github.com/labstack/echo/v5"
|
"github.com/labstack/echo/v5"
|
||||||
|
goqr "github.com/piglig/go-qr"
|
||||||
"github.com/pocketbase/pocketbase"
|
"github.com/pocketbase/pocketbase"
|
||||||
"github.com/pocketbase/pocketbase/apis"
|
"github.com/pocketbase/pocketbase/apis"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
|
Loading…
Reference in New Issue