mirror of
https://salsa.debian.org/mdosch/feed-to-muc.git
synced 2024-11-10 00:06:49 +01:00
Updated vendor packages.
This commit is contained in:
parent
15900057ad
commit
3d981156fe
11 changed files with 160 additions and 754 deletions
14
vendor/github.com/chilts/sid/ReadMe.md
generated
vendored
14
vendor/github.com/chilts/sid/ReadMe.md
generated
vendored
|
@ -20,13 +20,19 @@ go get github.com/chilts/sid
|
||||||
|
|
||||||
```
|
```
|
||||||
id1 := sid.Id()
|
id1 := sid.Id()
|
||||||
id2 := sid.Id()
|
id2 := sid.IdHex()
|
||||||
|
id3 := sid.IdBase32()
|
||||||
|
id4 := sid.IdBase64()
|
||||||
|
|
||||||
fmt.Printf("id1 = %s\n", id1)
|
fmt.Printf("id1 = %s\n", id1)
|
||||||
fmt.Printf("id2 = %s\n", id2)
|
fmt.Printf("id2 = %s\n", id2)
|
||||||
|
fmt.Printf("id3 = %s\n", id3)
|
||||||
|
fmt.Printf("id4 = %s\n", id4)
|
||||||
|
|
||||||
// -> "id1 = 1IeSBAWW83j-2wgJ4PUtlAr"
|
// -> "id1 = 1559872035903071353-1186579057231285506"
|
||||||
// -> "id2 = 1IeSBAWW9kK-0cDG64GQgGJ"
|
// -> "id2 = 15a5cf57e7d2a837-6eaafe687e7b3ec3"
|
||||||
|
// -> "id3 = 1b9efqnl51jj7-4u66ikpfq9ugm"
|
||||||
|
// -> "id4 = 1IeSBAWW9kK-0cDG64GQgGJ"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
@ -37,6 +43,6 @@ For [AppsAttic](https://appsattic.com/), [@AppsAttic](https://twitter.com/AppsAt
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT](https://publish.li/mit-qLQqmVTO).
|
[MIT](https://chilts.mit-license.org/2017/)
|
||||||
|
|
||||||
(Ends)
|
(Ends)
|
||||||
|
|
3
vendor/github.com/chilts/sid/go.mod
generated
vendored
Normal file
3
vendor/github.com/chilts/sid/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/chilts/sid
|
||||||
|
|
||||||
|
go 1.12
|
93
vendor/github.com/chilts/sid/sid.go
generated
vendored
93
vendor/github.com/chilts/sid/sid.go
generated
vendored
|
@ -12,6 +12,7 @@
|
||||||
package sid
|
package sid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -32,17 +33,39 @@ var chars = make([]string, 11, 11)
|
||||||
// 64 chars but ordered by ASCII
|
// 64 chars but ordered by ASCII
|
||||||
const base64 string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"
|
const base64 string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"
|
||||||
|
|
||||||
func toStr(now int64) string {
|
func toStr(n int64) string {
|
||||||
// now do the generation (backwards, so we just %64 then /64 along the way)
|
// now do the generation (backwards, so we just %64 then /64 along the way)
|
||||||
for i := 10; i >= 0; i-- {
|
for i := 10; i >= 0; i-- {
|
||||||
index := now % 64
|
index := n % 64
|
||||||
chars[i] = string(base64[index])
|
chars[i] = string(base64[index])
|
||||||
now = now / 64
|
n = n / 64
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(chars, "")
|
return strings.Join(chars, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toBase32(n int64) string {
|
||||||
|
b32 := strconv.FormatInt(n, 32)
|
||||||
|
|
||||||
|
for len(b32) < 13 {
|
||||||
|
b32 = "0" + b32
|
||||||
|
}
|
||||||
|
|
||||||
|
// log.Printf("b32=%s\n", b32)
|
||||||
|
|
||||||
|
return b32
|
||||||
|
}
|
||||||
|
|
||||||
|
func toHex(n int64) string {
|
||||||
|
hex := fmt.Sprintf("%x", n)
|
||||||
|
|
||||||
|
for len(hex) < 16 {
|
||||||
|
hex = "0" + hex
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex
|
||||||
|
}
|
||||||
|
|
||||||
// IdBase64 returns a 23 char string based on timestamp and a random number. The format is "XXXXXXXXXXX-YYYYYYYYYYY"
|
// IdBase64 returns a 23 char string based on timestamp and a random number. The format is "XXXXXXXXXXX-YYYYYYYYYYY"
|
||||||
// where X is the timestamp and Y is the random number. If (by any chance) this is called in the same nanosecond, the
|
// where X is the timestamp and Y is the random number. If (by any chance) this is called in the same nanosecond, the
|
||||||
// random number is incremented instead of a new one being generated. This makes sure that two consecutive Ids
|
// random number is incremented instead of a new one being generated. This makes sure that two consecutive Ids
|
||||||
|
@ -71,10 +94,66 @@ func IdBase64() string {
|
||||||
return toStr(now) + "-" + toStr(r)
|
return toStr(now) + "-" + toStr(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id returns a 23 char string based on timestamp and a random number. The format is "XXXXXXXXXXX-YYYYYYYYYYY" where X
|
// IdBase32 returns a 27 char string based on timestamp and a random number. The format is
|
||||||
// is the timestamp and Y is the random number. If (by any chance) this is called in the same nanosecond, the random
|
// "XXXXXXXXXXXXX-YYYYYYYYYYYYY" where X is the timestamp and Y is the random number. If (by any chance) this is called
|
||||||
// number is incremented instead of a new one being generated. This makes sure that two consecutive Ids generated in
|
// in the same nanosecond, the random number is incremented instead of a new one being generated. This makes sure that
|
||||||
// the same goroutine also ensure those Ids are also sortable.
|
// two consecutive Ids generated in the same goroutine also ensure those Ids are also sortable.
|
||||||
|
//
|
||||||
|
// It is safe to call from different goroutines since it has it's own locking.
|
||||||
|
func IdBase32() string {
|
||||||
|
// lock for lastTime, lastRand, and chars
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
now := time.Now().UTC().UnixNano()
|
||||||
|
var r int64
|
||||||
|
|
||||||
|
// if we have the same time, just inc lastRand, else create a new one
|
||||||
|
if now == lastTime {
|
||||||
|
lastRand++
|
||||||
|
} else {
|
||||||
|
lastRand = rand.Int63()
|
||||||
|
}
|
||||||
|
r = lastRand
|
||||||
|
|
||||||
|
// remember this for next time
|
||||||
|
lastTime = now
|
||||||
|
|
||||||
|
return toBase32(now) + "-" + toBase32(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IdHex returns a char string based on timestamp and a random number. The format is
|
||||||
|
// "XXXXXXXXXXXXXXXX-YYYYYYYYYYYYYYYY" where X is the timestamp and Y is the random number. If (by any chance) this is
|
||||||
|
// called in the same nanosecond, the random number is incremented instead of a new one being generated. This makes
|
||||||
|
// sure that two consecutive Ids generated in the same goroutine also ensure those Ids are also sortable.
|
||||||
|
//
|
||||||
|
// It is safe to call from different goroutines since it has it's own locking.
|
||||||
|
func IdHex() string {
|
||||||
|
// lock for lastTime, lastRand, and chars
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
now := time.Now().UTC().UnixNano()
|
||||||
|
var r int64
|
||||||
|
|
||||||
|
// if we have the same time, just inc lastRand, else create a new one
|
||||||
|
if now == lastTime {
|
||||||
|
lastRand++
|
||||||
|
} else {
|
||||||
|
lastRand = rand.Int63()
|
||||||
|
}
|
||||||
|
r = lastRand
|
||||||
|
|
||||||
|
// remember this for next time
|
||||||
|
lastTime = now
|
||||||
|
|
||||||
|
return toHex(now) + "-" + toHex(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Id returns a 39 char string based on timestamp and a random number. The format is
|
||||||
|
// "XXXXXXXXXXXXXXXXXXX-YYYYYYYYYYYYYYYYYYY" where X is the timestamp and Y is the random number. If (by any chance)
|
||||||
|
// this is called in the same nanosecond, the random number is incremented instead of a new one being generated. This
|
||||||
|
// makes sure that two consecutive Ids generated in the same goroutine also ensure those Ids are also sortable.
|
||||||
//
|
//
|
||||||
// It is safe to call from different goroutines since it has it's own locking.
|
// It is safe to call from different goroutines since it has it's own locking.
|
||||||
func Id() string {
|
func Id() string {
|
||||||
|
|
8
vendor/github.com/olekukonko/tablewriter/go.mod
generated
vendored
Normal file
8
vendor/github.com/olekukonko/tablewriter/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module github.com/olekukonko/tablewriter
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mattn/go-runewidth v0.0.4
|
||||||
|
github.com/olekukonko/tablewriter v0.0.1
|
||||||
|
)
|
4
vendor/github.com/olekukonko/tablewriter/go.sum
generated
vendored
Normal file
4
vendor/github.com/olekukonko/tablewriter/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
4
vendor/github.com/olekukonko/tablewriter/table.go
generated
vendored
4
vendor/github.com/olekukonko/tablewriter/table.go
generated
vendored
|
@ -766,7 +766,7 @@ func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, rowIdx
|
||||||
|
|
||||||
if t.autoMergeCells {
|
if t.autoMergeCells {
|
||||||
//Store the full line to merge mutli-lines cells
|
//Store the full line to merge mutli-lines cells
|
||||||
fullLine := strings.Join(columns[y], " ")
|
fullLine := strings.TrimRight(strings.Join(columns[y], " "), " ")
|
||||||
if len(previousLine) > y && fullLine == previousLine[y] && fullLine != "" {
|
if len(previousLine) > y && fullLine == previousLine[y] && fullLine != "" {
|
||||||
// If this cell is identical to the one above but not empty, we don't display the border and keep the cell empty.
|
// If this cell is identical to the one above but not empty, we don't display the border and keep the cell empty.
|
||||||
displayCellBorder = append(displayCellBorder, false)
|
displayCellBorder = append(displayCellBorder, false)
|
||||||
|
@ -804,7 +804,7 @@ func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, rowIdx
|
||||||
//The new previous line is the current one
|
//The new previous line is the current one
|
||||||
previousLine = make([]string, total)
|
previousLine = make([]string, total)
|
||||||
for y := 0; y < total; y++ {
|
for y := 0; y < total; y++ {
|
||||||
previousLine[y] = strings.Join(columns[y], " ") //Store the full line for multi-lines cells
|
previousLine[y] = strings.TrimRight(strings.Join(columns[y], " ")," ") //Store the full line for multi-lines cells
|
||||||
}
|
}
|
||||||
//Returns the newly added line and wether or not a border should be displayed above.
|
//Returns the newly added line and wether or not a border should be displayed above.
|
||||||
return previousLine, displayCellBorder
|
return previousLine, displayCellBorder
|
||||||
|
|
22
vendor/jaytaylor.com/html2text/LICENSE
generated
vendored
22
vendor/jaytaylor.com/html2text/LICENSE
generated
vendored
|
@ -1,22 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Jay Taylor
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
137
vendor/jaytaylor.com/html2text/README.md
generated
vendored
137
vendor/jaytaylor.com/html2text/README.md
generated
vendored
|
@ -1,137 +0,0 @@
|
||||||
# html2text
|
|
||||||
|
|
||||||
[![Documentation](https://godoc.org/github.com/jaytaylor/html2text?status.svg)](https://godoc.org/github.com/jaytaylor/html2text)
|
|
||||||
[![Build Status](https://travis-ci.org/jaytaylor/html2text.svg?branch=master)](https://travis-ci.org/jaytaylor/html2text)
|
|
||||||
[![Report Card](https://goreportcard.com/badge/github.com/jaytaylor/html2text)](https://goreportcard.com/report/github.com/jaytaylor/html2text)
|
|
||||||
|
|
||||||
### Converts HTML into text of the markdown-flavored variety
|
|
||||||
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Ensure your emails are readable by all!
|
|
||||||
|
|
||||||
Turns HTML into raw text, useful for sending fancy HTML emails with an equivalently nicely formatted TXT document as a fallback (e.g. for people who don't allow HTML emails or have other display issues).
|
|
||||||
|
|
||||||
html2text is a simple golang package for rendering HTML into plaintext.
|
|
||||||
|
|
||||||
There are still lots of improvements to be had, but FWIW this has worked fine for my [basic] HTML-2-text needs.
|
|
||||||
|
|
||||||
It requires go 1.x or newer ;)
|
|
||||||
|
|
||||||
|
|
||||||
## Download the package
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go get jaytaylor.com/html2text
|
|
||||||
```
|
|
||||||
|
|
||||||
## Example usage
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"jaytaylor.com/html2text"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
inputHTML := `
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>My Mega Service</title>
|
|
||||||
<link rel=\"stylesheet\" href=\"main.css\">
|
|
||||||
<style type=\"text/css\">body { color: #fff; }</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="logo">
|
|
||||||
<a href="http://jaytaylor.com/"><img src="/logo-image.jpg" alt="Mega Service"/></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1>Welcome to your new account on my service!</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Here is some more information:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Link 1: <a href="https://example.com">Example.com</a></li>
|
|
||||||
<li>Link 2: <a href="https://example2.com">Example2.com</a></li>
|
|
||||||
<li>Something else</li>
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr><th>Header 1</th><th>Header 2</th></tr>
|
|
||||||
</thead>
|
|
||||||
<tfoot>
|
|
||||||
<tr><td>Footer 1</td><td>Footer 2</td></tr>
|
|
||||||
</tfoot>
|
|
||||||
<tbody>
|
|
||||||
<tr><td>Row 1 Col 1</td><td>Row 1 Col 2</td></tr>
|
|
||||||
<tr><td>Row 2 Col 1</td><td>Row 2 Col 2</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>`
|
|
||||||
|
|
||||||
text, err := html2text.FromString(inputHTML, html2text.Options{PrettyTables: true})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Println(text)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
```
|
|
||||||
Mega Service ( http://jaytaylor.com/ )
|
|
||||||
|
|
||||||
******************************************
|
|
||||||
Welcome to your new account on my service!
|
|
||||||
******************************************
|
|
||||||
|
|
||||||
Here is some more information:
|
|
||||||
|
|
||||||
* Link 1: Example.com ( https://example.com )
|
|
||||||
* Link 2: Example2.com ( https://example2.com )
|
|
||||||
* Something else
|
|
||||||
|
|
||||||
+-------------+-------------+
|
|
||||||
| HEADER 1 | HEADER 2 |
|
|
||||||
+-------------+-------------+
|
|
||||||
| Row 1 Col 1 | Row 1 Col 2 |
|
|
||||||
| Row 2 Col 1 | Row 2 Col 2 |
|
|
||||||
+-------------+-------------+
|
|
||||||
| FOOTER 1 | FOOTER 2 |
|
|
||||||
+-------------+-------------+
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Unit-tests
|
|
||||||
|
|
||||||
Running the unit-tests is straightforward and standard:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go test
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# License
|
|
||||||
|
|
||||||
Permissive MIT license.
|
|
||||||
|
|
||||||
|
|
||||||
## Contact
|
|
||||||
|
|
||||||
You are more than welcome to open issues and send pull requests if you find a bug or want a new feature.
|
|
||||||
|
|
||||||
If you appreciate this library please feel free to drop me a line and tell me! It's always nice to hear from people who have benefitted from my work.
|
|
||||||
|
|
||||||
Email: jay at (my github username).com
|
|
||||||
|
|
||||||
Twitter: [@jtaylor](https://twitter.com/jtaylor)
|
|
||||||
|
|
535
vendor/jaytaylor.com/html2text/html2text.go
generated
vendored
535
vendor/jaytaylor.com/html2text/html2text.go
generated
vendored
|
@ -1,535 +0,0 @@
|
||||||
package html2text
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"github.com/olekukonko/tablewriter"
|
|
||||||
"github.com/ssor/bom"
|
|
||||||
"golang.org/x/net/html"
|
|
||||||
"golang.org/x/net/html/atom"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options provide toggles and overrides to control specific rendering behaviors.
|
|
||||||
type Options struct {
|
|
||||||
PrettyTables bool // Turns on pretty ASCII rendering for table elements.
|
|
||||||
PrettyTablesOptions *PrettyTablesOptions // Configures pretty ASCII rendering for table elements.
|
|
||||||
OmitLinks bool // Turns on omitting links
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrettyTablesOptions overrides tablewriter behaviors
|
|
||||||
type PrettyTablesOptions struct {
|
|
||||||
AutoFormatHeader bool
|
|
||||||
AutoWrapText bool
|
|
||||||
ReflowDuringAutoWrap bool
|
|
||||||
ColWidth int
|
|
||||||
ColumnSeparator string
|
|
||||||
RowSeparator string
|
|
||||||
CenterSeparator string
|
|
||||||
HeaderAlignment int
|
|
||||||
FooterAlignment int
|
|
||||||
Alignment int
|
|
||||||
ColumnAlignment []int
|
|
||||||
NewLine string
|
|
||||||
HeaderLine bool
|
|
||||||
RowLine bool
|
|
||||||
AutoMergeCells bool
|
|
||||||
Borders tablewriter.Border
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPrettyTablesOptions creates PrettyTablesOptions with default settings
|
|
||||||
func NewPrettyTablesOptions() *PrettyTablesOptions {
|
|
||||||
return &PrettyTablesOptions{
|
|
||||||
AutoFormatHeader: true,
|
|
||||||
AutoWrapText: true,
|
|
||||||
ReflowDuringAutoWrap: true,
|
|
||||||
ColWidth: tablewriter.MAX_ROW_WIDTH,
|
|
||||||
ColumnSeparator: tablewriter.COLUMN,
|
|
||||||
RowSeparator: tablewriter.ROW,
|
|
||||||
CenterSeparator: tablewriter.CENTER,
|
|
||||||
HeaderAlignment: tablewriter.ALIGN_DEFAULT,
|
|
||||||
FooterAlignment: tablewriter.ALIGN_DEFAULT,
|
|
||||||
Alignment: tablewriter.ALIGN_DEFAULT,
|
|
||||||
ColumnAlignment: []int{},
|
|
||||||
NewLine: tablewriter.NEWLINE,
|
|
||||||
HeaderLine: true,
|
|
||||||
RowLine: false,
|
|
||||||
AutoMergeCells: false,
|
|
||||||
Borders: tablewriter.Border{Left: true, Right: true, Bottom: true, Top: true},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromHTMLNode renders text output from a pre-parsed HTML document.
|
|
||||||
func FromHTMLNode(doc *html.Node, o ...Options) (string, error) {
|
|
||||||
var options Options
|
|
||||||
if len(o) > 0 {
|
|
||||||
options = o[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := textifyTraverseContext{
|
|
||||||
buf: bytes.Buffer{},
|
|
||||||
options: options,
|
|
||||||
}
|
|
||||||
if err := ctx.traverse(doc); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
text := strings.TrimSpace(newlineRe.ReplaceAllString(
|
|
||||||
strings.Replace(ctx.buf.String(), "\n ", "\n", -1), "\n\n"),
|
|
||||||
)
|
|
||||||
return text, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromReader renders text output after parsing HTML for the specified
|
|
||||||
// io.Reader.
|
|
||||||
func FromReader(reader io.Reader, options ...Options) (string, error) {
|
|
||||||
newReader, err := bom.NewReaderWithoutBom(reader)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
doc, err := html.Parse(newReader)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return FromHTMLNode(doc, options...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromString parses HTML from the input string, then renders the text form.
|
|
||||||
func FromString(input string, options ...Options) (string, error) {
|
|
||||||
bs := bom.CleanBom([]byte(input))
|
|
||||||
text, err := FromReader(bytes.NewReader(bs), options...)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return text, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
spacingRe = regexp.MustCompile(`[ \r\n\t]+`)
|
|
||||||
newlineRe = regexp.MustCompile(`\n\n+`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// traverseTableCtx holds text-related context.
|
|
||||||
type textifyTraverseContext struct {
|
|
||||||
buf bytes.Buffer
|
|
||||||
|
|
||||||
prefix string
|
|
||||||
tableCtx tableTraverseContext
|
|
||||||
options Options
|
|
||||||
endsWithSpace bool
|
|
||||||
justClosedDiv bool
|
|
||||||
blockquoteLevel int
|
|
||||||
lineLength int
|
|
||||||
isPre bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// tableTraverseContext holds table ASCII-form related context.
|
|
||||||
type tableTraverseContext struct {
|
|
||||||
header []string
|
|
||||||
body [][]string
|
|
||||||
footer []string
|
|
||||||
tmpRow int
|
|
||||||
isInFooter bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tableCtx *tableTraverseContext) init() {
|
|
||||||
tableCtx.body = [][]string{}
|
|
||||||
tableCtx.header = []string{}
|
|
||||||
tableCtx.footer = []string{}
|
|
||||||
tableCtx.isInFooter = false
|
|
||||||
tableCtx.tmpRow = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *textifyTraverseContext) handleElement(node *html.Node) error {
|
|
||||||
ctx.justClosedDiv = false
|
|
||||||
|
|
||||||
switch node.DataAtom {
|
|
||||||
case atom.Br:
|
|
||||||
return ctx.emit("\n")
|
|
||||||
|
|
||||||
case atom.H1, atom.H2, atom.H3:
|
|
||||||
subCtx := textifyTraverseContext{}
|
|
||||||
if err := subCtx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
str := subCtx.buf.String()
|
|
||||||
dividerLen := 0
|
|
||||||
for _, line := range strings.Split(str, "\n") {
|
|
||||||
if lineLen := len([]rune(line)); lineLen-1 > dividerLen {
|
|
||||||
dividerLen = lineLen - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var divider string
|
|
||||||
if node.DataAtom == atom.H1 {
|
|
||||||
divider = strings.Repeat("*", dividerLen)
|
|
||||||
} else {
|
|
||||||
divider = strings.Repeat("-", dividerLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.DataAtom == atom.H3 {
|
|
||||||
return ctx.emit("\n\n" + str + "\n" + divider + "\n\n")
|
|
||||||
}
|
|
||||||
return ctx.emit("\n\n" + divider + "\n" + str + "\n" + divider + "\n\n")
|
|
||||||
|
|
||||||
case atom.Blockquote:
|
|
||||||
ctx.blockquoteLevel++
|
|
||||||
ctx.prefix = strings.Repeat(">", ctx.blockquoteLevel) + " "
|
|
||||||
if err := ctx.emit("\n"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if ctx.blockquoteLevel == 1 {
|
|
||||||
if err := ctx.emit("\n"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := ctx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ctx.blockquoteLevel--
|
|
||||||
ctx.prefix = strings.Repeat(">", ctx.blockquoteLevel)
|
|
||||||
if ctx.blockquoteLevel > 0 {
|
|
||||||
ctx.prefix += " "
|
|
||||||
}
|
|
||||||
return ctx.emit("\n\n")
|
|
||||||
|
|
||||||
case atom.Div:
|
|
||||||
if ctx.lineLength > 0 {
|
|
||||||
if err := ctx.emit("\n"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := ctx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
if !ctx.justClosedDiv {
|
|
||||||
err = ctx.emit("\n")
|
|
||||||
}
|
|
||||||
ctx.justClosedDiv = true
|
|
||||||
return err
|
|
||||||
|
|
||||||
case atom.Li:
|
|
||||||
if err := ctx.emit("* "); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ctx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.emit("\n")
|
|
||||||
|
|
||||||
case atom.B, atom.Strong:
|
|
||||||
subCtx := textifyTraverseContext{}
|
|
||||||
subCtx.endsWithSpace = true
|
|
||||||
if err := subCtx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
str := subCtx.buf.String()
|
|
||||||
return ctx.emit("*" + str + "*")
|
|
||||||
|
|
||||||
case atom.A:
|
|
||||||
linkText := ""
|
|
||||||
// For simple link element content with single text node only, peek at the link text.
|
|
||||||
if node.FirstChild != nil && node.FirstChild.NextSibling == nil && node.FirstChild.Type == html.TextNode {
|
|
||||||
linkText = node.FirstChild.Data
|
|
||||||
}
|
|
||||||
|
|
||||||
// If image is the only child, take its alt text as the link text.
|
|
||||||
if img := node.FirstChild; img != nil && node.LastChild == img && img.DataAtom == atom.Img {
|
|
||||||
if altText := getAttrVal(img, "alt"); altText != "" {
|
|
||||||
if err := ctx.emit(altText); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if err := ctx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
hrefLink := ""
|
|
||||||
if attrVal := getAttrVal(node, "href"); attrVal != "" {
|
|
||||||
attrVal = ctx.normalizeHrefLink(attrVal)
|
|
||||||
// Don't print link href if it matches link element content or if the link is empty.
|
|
||||||
if !ctx.options.OmitLinks && attrVal != "" && linkText != attrVal {
|
|
||||||
hrefLink = "( " + attrVal + " )"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.emit(hrefLink)
|
|
||||||
|
|
||||||
case atom.P, atom.Ul:
|
|
||||||
return ctx.paragraphHandler(node)
|
|
||||||
|
|
||||||
case atom.Table, atom.Tfoot, atom.Th, atom.Tr, atom.Td:
|
|
||||||
if ctx.options.PrettyTables {
|
|
||||||
return ctx.handleTableElement(node)
|
|
||||||
} else if node.DataAtom == atom.Table {
|
|
||||||
return ctx.paragraphHandler(node)
|
|
||||||
}
|
|
||||||
return ctx.traverseChildren(node)
|
|
||||||
|
|
||||||
case atom.Pre:
|
|
||||||
ctx.isPre = true
|
|
||||||
err := ctx.traverseChildren(node)
|
|
||||||
ctx.isPre = false
|
|
||||||
return err
|
|
||||||
|
|
||||||
case atom.Style, atom.Script, atom.Head:
|
|
||||||
// Ignore the subtree.
|
|
||||||
return nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
return ctx.traverseChildren(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// paragraphHandler renders node children surrounded by double newlines.
|
|
||||||
func (ctx *textifyTraverseContext) paragraphHandler(node *html.Node) error {
|
|
||||||
if err := ctx.emit("\n\n"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := ctx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return ctx.emit("\n\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleTableElement is only to be invoked when options.PrettyTables is active.
|
|
||||||
func (ctx *textifyTraverseContext) handleTableElement(node *html.Node) error {
|
|
||||||
if !ctx.options.PrettyTables {
|
|
||||||
panic("handleTableElement invoked when PrettyTables not active")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch node.DataAtom {
|
|
||||||
case atom.Table:
|
|
||||||
if err := ctx.emit("\n\n"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-intialize all table context.
|
|
||||||
ctx.tableCtx.init()
|
|
||||||
|
|
||||||
// Browse children, enriching context with table data.
|
|
||||||
if err := ctx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
table := tablewriter.NewWriter(buf)
|
|
||||||
if ctx.options.PrettyTablesOptions != nil {
|
|
||||||
options := ctx.options.PrettyTablesOptions
|
|
||||||
table.SetAutoFormatHeaders(options.AutoFormatHeader)
|
|
||||||
table.SetAutoWrapText(options.AutoWrapText)
|
|
||||||
table.SetReflowDuringAutoWrap(options.ReflowDuringAutoWrap)
|
|
||||||
table.SetColWidth(options.ColWidth)
|
|
||||||
table.SetColumnSeparator(options.ColumnSeparator)
|
|
||||||
table.SetRowSeparator(options.RowSeparator)
|
|
||||||
table.SetCenterSeparator(options.CenterSeparator)
|
|
||||||
table.SetHeaderAlignment(options.HeaderAlignment)
|
|
||||||
table.SetFooterAlignment(options.FooterAlignment)
|
|
||||||
table.SetAlignment(options.Alignment)
|
|
||||||
table.SetColumnAlignment(options.ColumnAlignment)
|
|
||||||
table.SetNewLine(options.NewLine)
|
|
||||||
table.SetHeaderLine(options.HeaderLine)
|
|
||||||
table.SetRowLine(options.RowLine)
|
|
||||||
table.SetAutoMergeCells(options.AutoMergeCells)
|
|
||||||
table.SetBorders(options.Borders)
|
|
||||||
}
|
|
||||||
table.SetHeader(ctx.tableCtx.header)
|
|
||||||
table.SetFooter(ctx.tableCtx.footer)
|
|
||||||
table.AppendBulk(ctx.tableCtx.body)
|
|
||||||
|
|
||||||
// Render the table using ASCII.
|
|
||||||
table.Render()
|
|
||||||
if err := ctx.emit(buf.String()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.emit("\n\n")
|
|
||||||
|
|
||||||
case atom.Tfoot:
|
|
||||||
ctx.tableCtx.isInFooter = true
|
|
||||||
if err := ctx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ctx.tableCtx.isInFooter = false
|
|
||||||
|
|
||||||
case atom.Tr:
|
|
||||||
ctx.tableCtx.body = append(ctx.tableCtx.body, []string{})
|
|
||||||
if err := ctx.traverseChildren(node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ctx.tableCtx.tmpRow++
|
|
||||||
|
|
||||||
case atom.Th:
|
|
||||||
res, err := ctx.renderEachChild(node)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.tableCtx.header = append(ctx.tableCtx.header, res)
|
|
||||||
|
|
||||||
case atom.Td:
|
|
||||||
res, err := ctx.renderEachChild(node)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.tableCtx.isInFooter {
|
|
||||||
ctx.tableCtx.footer = append(ctx.tableCtx.footer, res)
|
|
||||||
} else {
|
|
||||||
ctx.tableCtx.body[ctx.tableCtx.tmpRow] = append(ctx.tableCtx.body[ctx.tableCtx.tmpRow], res)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *textifyTraverseContext) traverse(node *html.Node) error {
|
|
||||||
switch node.Type {
|
|
||||||
default:
|
|
||||||
return ctx.traverseChildren(node)
|
|
||||||
|
|
||||||
case html.TextNode:
|
|
||||||
var data string
|
|
||||||
if ctx.isPre {
|
|
||||||
data = node.Data
|
|
||||||
} else {
|
|
||||||
data = strings.TrimSpace(spacingRe.ReplaceAllString(node.Data, " "))
|
|
||||||
}
|
|
||||||
return ctx.emit(data)
|
|
||||||
|
|
||||||
case html.ElementNode:
|
|
||||||
return ctx.handleElement(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *textifyTraverseContext) traverseChildren(node *html.Node) error {
|
|
||||||
for c := node.FirstChild; c != nil; c = c.NextSibling {
|
|
||||||
if err := ctx.traverse(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *textifyTraverseContext) emit(data string) error {
|
|
||||||
if data == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
lines = ctx.breakLongLines(data)
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
for _, line := range lines {
|
|
||||||
runes := []rune(line)
|
|
||||||
startsWithSpace := unicode.IsSpace(runes[0])
|
|
||||||
if !startsWithSpace && !ctx.endsWithSpace && !strings.HasPrefix(data, ".") {
|
|
||||||
if err = ctx.buf.WriteByte(' '); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ctx.lineLength++
|
|
||||||
}
|
|
||||||
ctx.endsWithSpace = unicode.IsSpace(runes[len(runes)-1])
|
|
||||||
for _, c := range line {
|
|
||||||
if _, err = ctx.buf.WriteString(string(c)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ctx.lineLength++
|
|
||||||
if c == '\n' {
|
|
||||||
ctx.lineLength = 0
|
|
||||||
if ctx.prefix != "" {
|
|
||||||
if _, err = ctx.buf.WriteString(ctx.prefix); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxLineLen = 74
|
|
||||||
|
|
||||||
func (ctx *textifyTraverseContext) breakLongLines(data string) []string {
|
|
||||||
// Only break lines when in blockquotes.
|
|
||||||
if ctx.blockquoteLevel == 0 {
|
|
||||||
return []string{data}
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
ret = []string{}
|
|
||||||
runes = []rune(data)
|
|
||||||
l = len(runes)
|
|
||||||
existing = ctx.lineLength
|
|
||||||
)
|
|
||||||
if existing >= maxLineLen {
|
|
||||||
ret = append(ret, "\n")
|
|
||||||
existing = 0
|
|
||||||
}
|
|
||||||
for l+existing > maxLineLen {
|
|
||||||
i := maxLineLen - existing
|
|
||||||
for i >= 0 && !unicode.IsSpace(runes[i]) {
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
if i == -1 {
|
|
||||||
// No spaces, so go the other way.
|
|
||||||
i = maxLineLen - existing
|
|
||||||
for i < l && !unicode.IsSpace(runes[i]) {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = append(ret, string(runes[:i])+"\n")
|
|
||||||
for i < l && unicode.IsSpace(runes[i]) {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
runes = runes[i:]
|
|
||||||
l = len(runes)
|
|
||||||
existing = 0
|
|
||||||
}
|
|
||||||
if len(runes) > 0 {
|
|
||||||
ret = append(ret, string(runes))
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *textifyTraverseContext) normalizeHrefLink(link string) string {
|
|
||||||
link = strings.TrimSpace(link)
|
|
||||||
link = strings.TrimPrefix(link, "mailto:")
|
|
||||||
return link
|
|
||||||
}
|
|
||||||
|
|
||||||
// renderEachChild visits each direct child of a node and collects the sequence of
|
|
||||||
// textuual representaitons separated by a single newline.
|
|
||||||
func (ctx *textifyTraverseContext) renderEachChild(node *html.Node) (string, error) {
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
for c := node.FirstChild; c != nil; c = c.NextSibling {
|
|
||||||
s, err := FromHTMLNode(c, ctx.options)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if _, err = buf.WriteString(s); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if c.NextSibling != nil {
|
|
||||||
if err = buf.WriteByte('\n'); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAttrVal(node *html.Node, attrName string) string {
|
|
||||||
for _, attr := range node.Attr {
|
|
||||||
if attr.Key == attrName {
|
|
||||||
return attr.Val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
92
vendor/vendor.json
vendored
92
vendor/vendor.json
vendored
|
@ -15,10 +15,10 @@
|
||||||
"revisionTime": "2018-10-12T15:44:24Z"
|
"revisionTime": "2018-10-12T15:44:24Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "5UWAX/5F5bqC7tKtDb2QFFRqwAs=",
|
"checksumSHA1": "WoatyvsqqryIUsNP+2fXlbVtAVM=",
|
||||||
"path": "github.com/chilts/sid",
|
"path": "github.com/chilts/sid",
|
||||||
"revision": "250d10e55bf450834d37cb13b7dae8816ada9b28",
|
"revision": "660e94789ec9b45634f588d40881e81b56de92a0",
|
||||||
"revisionTime": "2018-09-28T23:21:30Z"
|
"revisionTime": "2019-06-07T04:24:30Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "qR7D38Zmn9TPUvGn64k+r0+Kq1c=",
|
"checksumSHA1": "qR7D38Zmn9TPUvGn64k+r0+Kq1c=",
|
||||||
|
@ -69,10 +69,10 @@
|
||||||
"revisionTime": "2018-10-12T15:49:47Z"
|
"revisionTime": "2018-10-12T15:49:47Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "HZJ2dhzXoMi8n+iY80A9vsnyQUk=",
|
"checksumSHA1": "C2jnBks3LctebwDmLMoq/zYZex0=",
|
||||||
"path": "github.com/olekukonko/tablewriter",
|
"path": "github.com/olekukonko/tablewriter",
|
||||||
"revision": "1c0837c15a0bac7871496dfce5dcdd308e0a330f",
|
"revision": "cc27d85e17cec9768d2ac401ea5d619a9628f16d",
|
||||||
"revisionTime": "2019-05-08T01:39:46Z"
|
"revisionTime": "2019-06-18T03:32:46Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "qErubHtC7DAFBnEQkMTuKDtfFTU=",
|
"checksumSHA1": "qErubHtC7DAFBnEQkMTuKDtfFTU=",
|
||||||
|
@ -83,122 +83,122 @@
|
||||||
{
|
{
|
||||||
"checksumSHA1": "bONEZcbkYKiPyABrecOLzHomjPU=",
|
"checksumSHA1": "bONEZcbkYKiPyABrecOLzHomjPU=",
|
||||||
"path": "golang.org/x/net/html",
|
"path": "golang.org/x/net/html",
|
||||||
"revision": "f3200d17e092c607f615320ecaad13d87ad9a2b3",
|
"revision": "ba9fcec4b297b415637633c5a6e8fa592e4a16c3",
|
||||||
"revisionTime": "2019-05-22T15:39:15Z"
|
"revisionTime": "2019-08-26T16:14:39Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "xwhqe/igHQrY3IhqDwzo6j7qpm8=",
|
"checksumSHA1": "xwhqe/igHQrY3IhqDwzo6j7qpm8=",
|
||||||
"path": "golang.org/x/net/html/atom",
|
"path": "golang.org/x/net/html/atom",
|
||||||
"revision": "f3200d17e092c607f615320ecaad13d87ad9a2b3",
|
"revision": "ba9fcec4b297b415637633c5a6e8fa592e4a16c3",
|
||||||
"revisionTime": "2019-05-22T15:39:15Z"
|
"revisionTime": "2019-08-26T16:14:39Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "barUU39reQ7LdgYLA323hQ/UGy4=",
|
"checksumSHA1": "barUU39reQ7LdgYLA323hQ/UGy4=",
|
||||||
"path": "golang.org/x/net/html/charset",
|
"path": "golang.org/x/net/html/charset",
|
||||||
"revision": "f3200d17e092c607f615320ecaad13d87ad9a2b3",
|
"revision": "ba9fcec4b297b415637633c5a6e8fa592e4a16c3",
|
||||||
"revisionTime": "2019-05-22T15:39:15Z"
|
"revisionTime": "2019-08-26T16:14:39Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "tqqo7DEeFCclb58XbN44WwdpWww=",
|
"checksumSHA1": "tqqo7DEeFCclb58XbN44WwdpWww=",
|
||||||
"path": "golang.org/x/text/encoding",
|
"path": "golang.org/x/text/encoding",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "DSdlK4MKI/a3U8Zaee2XKBe01Fo=",
|
"checksumSHA1": "DSdlK4MKI/a3U8Zaee2XKBe01Fo=",
|
||||||
"path": "golang.org/x/text/encoding/charmap",
|
"path": "golang.org/x/text/encoding/charmap",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "SbJkfe5G/5tji96Pa15/ePDOCtk=",
|
"checksumSHA1": "SbJkfe5G/5tji96Pa15/ePDOCtk=",
|
||||||
"path": "golang.org/x/text/encoding/htmlindex",
|
"path": "golang.org/x/text/encoding/htmlindex",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "zeHyHebIZl1tGuwGllIhjfci+wI=",
|
"checksumSHA1": "zeHyHebIZl1tGuwGllIhjfci+wI=",
|
||||||
"path": "golang.org/x/text/encoding/internal",
|
"path": "golang.org/x/text/encoding/internal",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "hT7VaIBlkm2YpKulgnjqXNdicGQ=",
|
"checksumSHA1": "hT7VaIBlkm2YpKulgnjqXNdicGQ=",
|
||||||
"path": "golang.org/x/text/encoding/internal/identifier",
|
"path": "golang.org/x/text/encoding/internal/identifier",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "2YqVpmvjWGEBATyUphTP1MS34JE=",
|
"checksumSHA1": "2YqVpmvjWGEBATyUphTP1MS34JE=",
|
||||||
"path": "golang.org/x/text/encoding/japanese",
|
"path": "golang.org/x/text/encoding/japanese",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "+ErWCAdaMwO4PLtrk9D/Hh+7oQM=",
|
"checksumSHA1": "+ErWCAdaMwO4PLtrk9D/Hh+7oQM=",
|
||||||
"path": "golang.org/x/text/encoding/korean",
|
"path": "golang.org/x/text/encoding/korean",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "mTuZi5urYwgDIO8+Gfql2pv8Vwg=",
|
"checksumSHA1": "mTuZi5urYwgDIO8+Gfql2pv8Vwg=",
|
||||||
"path": "golang.org/x/text/encoding/simplifiedchinese",
|
"path": "golang.org/x/text/encoding/simplifiedchinese",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "D+VI4j0Wjzr8SeupWdOB5KBdFOw=",
|
"checksumSHA1": "D+VI4j0Wjzr8SeupWdOB5KBdFOw=",
|
||||||
"path": "golang.org/x/text/encoding/traditionalchinese",
|
"path": "golang.org/x/text/encoding/traditionalchinese",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "bAJTZJ3IGJdNmN/PSlRMRxWtxec=",
|
"checksumSHA1": "bAJTZJ3IGJdNmN/PSlRMRxWtxec=",
|
||||||
"path": "golang.org/x/text/encoding/unicode",
|
"path": "golang.org/x/text/encoding/unicode",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "ybE4kAPmNPV/dvShuG86AmLbhdE=",
|
"checksumSHA1": "ybE4kAPmNPV/dvShuG86AmLbhdE=",
|
||||||
"path": "golang.org/x/text/internal/language",
|
"path": "golang.org/x/text/internal/language",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "VDwNSsZP6KShjTSwGUQUGJVrs1I=",
|
"checksumSHA1": "VDwNSsZP6KShjTSwGUQUGJVrs1I=",
|
||||||
"path": "golang.org/x/text/internal/language/compact",
|
"path": "golang.org/x/text/internal/language/compact",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "hyNCcTwMQnV6/MK8uUW9E5H0J0M=",
|
"checksumSHA1": "hyNCcTwMQnV6/MK8uUW9E5H0J0M=",
|
||||||
"path": "golang.org/x/text/internal/tag",
|
"path": "golang.org/x/text/internal/tag",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "Qk7dljcrEK1BJkAEZguxAbG9dSo=",
|
"checksumSHA1": "Qk7dljcrEK1BJkAEZguxAbG9dSo=",
|
||||||
"path": "golang.org/x/text/internal/utf8internal",
|
"path": "golang.org/x/text/internal/utf8internal",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "oYNlkS+0TimKOScUz3Hn9QWyz6w=",
|
"checksumSHA1": "oYNlkS+0TimKOScUz3Hn9QWyz6w=",
|
||||||
"path": "golang.org/x/text/language",
|
"path": "golang.org/x/text/language",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "IV4MN7KGBSocu/5NR3le3sxup4Y=",
|
"checksumSHA1": "IV4MN7KGBSocu/5NR3le3sxup4Y=",
|
||||||
"path": "golang.org/x/text/runes",
|
"path": "golang.org/x/text/runes",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "R9iBDY+aPnT+8pyRcqGjXq5QixA=",
|
"checksumSHA1": "R9iBDY+aPnT+8pyRcqGjXq5QixA=",
|
||||||
"path": "golang.org/x/text/transform",
|
"path": "golang.org/x/text/transform",
|
||||||
"revision": "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
"revision": "3d0f7978add91030e5e8976ff65ccdd828286cba",
|
||||||
"revisionTime": "2018-12-15T17:52:45Z"
|
"revisionTime": "2019-08-29T15:11:34Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "2/9hMw7Y4I42L/PTobKqVldWUAU=",
|
"checksumSHA1": "2/9hMw7Y4I42L/PTobKqVldWUAU=",
|
||||||
|
|
Loading…
Reference in a new issue