forked from lug/matterbridge
		
	Compare commits
	
		
			25 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					214fe502cd | ||
| 
						 | 
					aae45a8179 | ||
| 
						 | 
					075ca9ca47 | ||
| 
						 | 
					d4253d7a55 | ||
| 
						 | 
					0917dc8766 | ||
| 
						 | 
					aba86855b5 | ||
| 
						 | 
					ed5386c213 | ||
| 
						 | 
					455e75e92f | ||
| 
						 | 
					c394de0c88 | ||
| 
						 | 
					bad1990173 | ||
| 
						 | 
					0bc159341d | ||
| 
						 | 
					45bf1fd63a | ||
| 
						 | 
					ff0de85817 | ||
| 
						 | 
					727fa9f929 | ||
| 
						 | 
					0b9bc18236 | ||
| 
						 | 
					bad3b83d33 | ||
| 
						 | 
					00967a98ac | ||
| 
						 | 
					1d708ab351 | ||
| 
						 | 
					ba6759010b | ||
| 
						 | 
					da3868c104 | ||
| 
						 | 
					0abf4d5d5d | ||
| 
						 | 
					9b320cd43f | ||
| 
						 | 
					28783a4146 | ||
| 
						 | 
					f92927eae5 | ||
| 
						 | 
					294139ce7a | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,4 @@
 | 
			
		||||
# Exclude matterbridge binary
 | 
			
		||||
matterbridge
 | 
			
		||||
 | 
			
		||||
# Exclude configuration file
 | 
			
		||||
matterbridge.toml
 | 
			
		||||
 
 | 
			
		||||
@@ -174,6 +174,7 @@ linters:
 | 
			
		||||
    - lll
 | 
			
		||||
    - maligned
 | 
			
		||||
    - prealloc
 | 
			
		||||
    - wsl
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# rules to deal with reported isues
 | 
			
		||||
 
 | 
			
		||||
@@ -21,14 +21,18 @@ builds:
 | 
			
		||||
  ldflags:
 | 
			
		||||
    - -s -w -X main.githash={{.ShortCommit}}
 | 
			
		||||
 | 
			
		||||
archive:
 | 
			
		||||
  name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
 | 
			
		||||
  format: binary
 | 
			
		||||
  files:
 | 
			
		||||
    - none*
 | 
			
		||||
  replacements:
 | 
			
		||||
    386: 32bit
 | 
			
		||||
    amd64: 64bit
 | 
			
		||||
archives:
 | 
			
		||||
  -
 | 
			
		||||
    id: matterbridge
 | 
			
		||||
    builds:
 | 
			
		||||
    - matterbridge
 | 
			
		||||
    name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
 | 
			
		||||
    format: binary
 | 
			
		||||
    files:
 | 
			
		||||
      - none*
 | 
			
		||||
    replacements:
 | 
			
		||||
      386: 32bit
 | 
			
		||||
      amd64: 64bit
 | 
			
		||||
 | 
			
		||||
checksum:
 | 
			
		||||
  name_template: 'checksums.txt'
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -20,22 +20,22 @@ jobs:
 | 
			
		||||
  - stage: lint
 | 
			
		||||
    # Run linting in one Go environment only.
 | 
			
		||||
    script: ./ci/lint.sh
 | 
			
		||||
    go: 1.12.x
 | 
			
		||||
    go: 1.13.x
 | 
			
		||||
    env:
 | 
			
		||||
    - GO111MODULE=on
 | 
			
		||||
    - GOLANGCI_VERSION="v1.17.1"
 | 
			
		||||
    - GOLANGCI_VERSION="v1.21.0"
 | 
			
		||||
  - stage: test
 | 
			
		||||
    # Run tests in a combination of Go environments.
 | 
			
		||||
    script: ./ci/test.sh
 | 
			
		||||
    go: 1.11.x
 | 
			
		||||
    go: 1.12.x
 | 
			
		||||
    env:
 | 
			
		||||
    - GO111MODULE=off
 | 
			
		||||
  - script: ./ci/test.sh
 | 
			
		||||
    go: 1.11.x
 | 
			
		||||
    go: 1.12.x
 | 
			
		||||
    env:
 | 
			
		||||
    - GO111MODULE=on
 | 
			
		||||
  - script: ./ci/test.sh
 | 
			
		||||
    go: 1.12.x
 | 
			
		||||
    go: 1.13.x
 | 
			
		||||
    env:
 | 
			
		||||
    - GO111MODULE=on
 | 
			
		||||
    - REPORT_COVERAGE=1
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							@@ -102,6 +102,7 @@ And more...
 | 
			
		||||
- [Reddit](https://github.com/bonehurtingjuice/mattereddit)
 | 
			
		||||
- [Facebook messenger](https://github.com/VictorNine/fbridge)
 | 
			
		||||
- [Discourse](https://github.com/DeclanHoare/matterbabble)
 | 
			
		||||
- [Counter-Strike, half-life and more](https://forums.alliedmods.net/showthread.php?t=319430)
 | 
			
		||||
 | 
			
		||||
### API
 | 
			
		||||
 | 
			
		||||
@@ -115,6 +116,7 @@ Used by the projects below. Feel free to make a PR to add your project to this l
 | 
			
		||||
- [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support)
 | 
			
		||||
- [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support)
 | 
			
		||||
- [matterbabble](https://github.com/DeclanHoare/matterbabble) (Discourse support)
 | 
			
		||||
- [MatterAMXX](https://forums.alliedmods.net/showthread.php?t=319430) (Counter-Strike, half-life and more via AMXX mod)
 | 
			
		||||
 | 
			
		||||
## Chat with us
 | 
			
		||||
 | 
			
		||||
@@ -140,7 +142,7 @@ See https://github.com/42wim/matterbridge/wiki
 | 
			
		||||
 | 
			
		||||
### Binaries
 | 
			
		||||
 | 
			
		||||
- Latest stable release [v1.16.0](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
- Latest stable release [v1.16.2](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
- Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
 | 
			
		||||
 | 
			
		||||
To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest) and follow the instructions on the [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
 | 
			
		||||
@@ -154,19 +156,17 @@ To install or upgrade just download the latest [binary](https://github.com/42wim
 | 
			
		||||
Most people just want to use binaries, you can find those [here](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
 | 
			
		||||
If you really want to build from source, follow these instructions:
 | 
			
		||||
Go 1.9+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH](https://golang.org/doc/code.html#GOPATH).
 | 
			
		||||
Go 1.12+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed.
 | 
			
		||||
 | 
			
		||||
After Go is setup, download matterbridge to your \$GOPATH directory.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
cd $GOPATH
 | 
			
		||||
go get github.com/42wim/matterbridge
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You should now have matterbridge binary in the bin directory:
 | 
			
		||||
You should now have matterbridge binary in the ~/go/bin directory:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ ls bin/
 | 
			
		||||
$ ls ~/go/bin/
 | 
			
		||||
matterbridge
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -206,6 +206,7 @@ type BridgeValues struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Config interface {
 | 
			
		||||
	Viper() *viper.Viper
 | 
			
		||||
	BridgeValues() *BridgeValues
 | 
			
		||||
	GetBool(key string) (bool, bool)
 | 
			
		||||
	GetInt(key string) (int, bool)
 | 
			
		||||
@@ -274,6 +275,10 @@ func (c *config) BridgeValues() *BridgeValues {
 | 
			
		||||
	return c.cv
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *config) Viper() *viper.Viper {
 | 
			
		||||
	return c.v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *config) GetBool(key string) (bool, bool) {
 | 
			
		||||
	c.RLock()
 | 
			
		||||
	defer c.RUnlock()
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,7 @@ func (b *Bdiscord) Connect() error {
 | 
			
		||||
	}
 | 
			
		||||
	b.Log.Info("Connection succeeded")
 | 
			
		||||
	b.c.AddHandler(b.messageCreate)
 | 
			
		||||
	b.c.AddHandler(b.messageTyping)
 | 
			
		||||
	b.c.AddHandler(b.memberUpdate)
 | 
			
		||||
	b.c.AddHandler(b.messageUpdate)
 | 
			
		||||
	b.c.AddHandler(b.messageDelete)
 | 
			
		||||
@@ -188,6 +189,14 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
 | 
			
		||||
		return "", fmt.Errorf("Could not find channelID for %v", msg.Channel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if msg.Event == config.EventUserTyping {
 | 
			
		||||
		if b.GetBool("ShowUserTyping") {
 | 
			
		||||
			err := b.c.ChannelTyping(channelID)
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Make a action /me of the message
 | 
			
		||||
	if msg.Event == config.EventUserAction {
 | 
			
		||||
		msg.Text = "_" + msg.Text + "_"
 | 
			
		||||
@@ -225,18 +234,6 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		b.Log.Debugf("Broadcasting using Webhook")
 | 
			
		||||
		for _, f := range msg.Extra["file"] {
 | 
			
		||||
			fi := f.(config.FileInfo)
 | 
			
		||||
			if fi.Comment != "" {
 | 
			
		||||
				msg.Text += fi.Comment + ": "
 | 
			
		||||
			}
 | 
			
		||||
			if fi.URL != "" {
 | 
			
		||||
				msg.Text = fi.URL
 | 
			
		||||
				if fi.Comment != "" {
 | 
			
		||||
					msg.Text = fi.Comment + ": " + fi.URL
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// skip empty messages
 | 
			
		||||
		if msg.Text == "" && (msg.Extra == nil || len(msg.Extra["file"]) == 0) {
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,19 @@ func (b *Bdiscord) messageDeleteBulk(s *discordgo.Session, m *discordgo.MessageD
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) messageTyping(s *discordgo.Session, m *discordgo.TypingStart) {
 | 
			
		||||
	if !b.GetBool("ShowUserTyping") {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rmsg := config.Message{Account: b.Account, Event: config.EventUserTyping}
 | 
			
		||||
	rmsg.Channel = b.getChannelName(m.ChannelID)
 | 
			
		||||
	if b.useChannelID {
 | 
			
		||||
		rmsg.Channel = "ID:" + m.ChannelID
 | 
			
		||||
	}
 | 
			
		||||
	b.Remote <- rmsg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) { //nolint:unparam
 | 
			
		||||
	if b.GetBool("EditDisable") {
 | 
			
		||||
		return
 | 
			
		||||
@@ -45,7 +58,10 @@ func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdat
 | 
			
		||||
	if m.Message.EditedTimestamp != "" {
 | 
			
		||||
		b.Log.Debugf("Sending edit message")
 | 
			
		||||
		m.Content += b.GetString("EditSuffix")
 | 
			
		||||
		b.messageCreate(s, (*discordgo.MessageCreate)(m))
 | 
			
		||||
		msg := &discordgo.MessageCreate{
 | 
			
		||||
			Message: m.Message,
 | 
			
		||||
		}
 | 
			
		||||
		b.messageCreate(s, msg)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -89,7 +105,7 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
 | 
			
		||||
 | 
			
		||||
	// set username
 | 
			
		||||
	if !b.GetBool("UseUserName") {
 | 
			
		||||
		rmsg.Username = b.getNick(m.Author)
 | 
			
		||||
		rmsg.Username = b.getNick(m.Author, m.GuildID)
 | 
			
		||||
	} else {
 | 
			
		||||
		rmsg.Username = m.Author.Username
 | 
			
		||||
		if b.GetBool("UseDiscriminator") {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import (
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *Bdiscord) getNick(user *discordgo.User) string {
 | 
			
		||||
func (b *Bdiscord) getNick(user *discordgo.User, guildID string) string {
 | 
			
		||||
	b.membersMutex.RLock()
 | 
			
		||||
	defer b.membersMutex.RUnlock()
 | 
			
		||||
 | 
			
		||||
@@ -23,9 +23,9 @@ func (b *Bdiscord) getNick(user *discordgo.User) string {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If we didn't find nick, search for it.
 | 
			
		||||
	member, err := b.c.GuildMember(b.guildID, user.ID)
 | 
			
		||||
	member, err := b.c.GuildMember(guildID, user.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Warnf("Failed to fetch information for member %#v on guild %#v: %s", user, b.guildID, err)
 | 
			
		||||
		b.Log.Warnf("Failed to fetch information for member %#v on guild %#v: %s", user, guildID, err)
 | 
			
		||||
		return user.Username
 | 
			
		||||
	} else if member == nil {
 | 
			
		||||
		b.Log.Warnf("Got no information for member %#v", user)
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,9 @@ import (
 | 
			
		||||
	"golang.org/x/image/webp"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/gomarkdown/markdown"
 | 
			
		||||
	"github.com/gomarkdown/markdown/parser"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
	"gitlab.com/golang-commonmark/markdown"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DownloadFile downloads the given non-authenticated URL.
 | 
			
		||||
@@ -176,9 +177,12 @@ func ClipMessage(text string, length int) string {
 | 
			
		||||
	return text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseMarkdown takes in an input string as markdown and parses it to html
 | 
			
		||||
func ParseMarkdown(input string) string {
 | 
			
		||||
	md := markdown.New(markdown.XHTMLOutput(true), markdown.Breaks(true))
 | 
			
		||||
	res := md.RenderToString([]byte(input))
 | 
			
		||||
	extensions := parser.HardLineBreak
 | 
			
		||||
	markdownParser := parser.NewWithExtensions(extensions)
 | 
			
		||||
	parsedMarkdown := markdown.ToHTML([]byte(input), markdownParser, nil)
 | 
			
		||||
	res := string(parsedMarkdown)
 | 
			
		||||
	res = strings.TrimPrefix(res, "<p>")
 | 
			
		||||
	res = strings.TrimSuffix(res, "</p>\n")
 | 
			
		||||
	return res
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,9 @@
 | 
			
		||||
package bkeybase
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge"
 | 
			
		||||
@@ -66,17 +69,37 @@ func (b *Bkeybase) Send(msg config.Message) (string, error) {
 | 
			
		||||
	// Delete message if we have an ID
 | 
			
		||||
	// Delete message not supported by keybase go library yet
 | 
			
		||||
 | 
			
		||||
	// Upload a file if it exists
 | 
			
		||||
	// kbchat lib does not support attachments yet
 | 
			
		||||
 | 
			
		||||
	// Edit message if we have an ID
 | 
			
		||||
	// kbchat lib does not support message editing yet
 | 
			
		||||
 | 
			
		||||
	if len(msg.Extra["file"]) > 0 {
 | 
			
		||||
		// Upload a file
 | 
			
		||||
		dir, err := ioutil.TempDir("", "matterbridge")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		defer os.RemoveAll(dir)
 | 
			
		||||
 | 
			
		||||
		for _, f := range msg.Extra["file"] {
 | 
			
		||||
			fname := f.(config.FileInfo).Name
 | 
			
		||||
			fdata := *f.(config.FileInfo).Data
 | 
			
		||||
			fcaption := f.(config.FileInfo).Comment
 | 
			
		||||
			fpath := filepath.Join(dir, fname)
 | 
			
		||||
 | 
			
		||||
			if err = ioutil.WriteFile(fpath, fdata, 0600); err != nil {
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, _ = b.kbc.SendAttachmentByTeam(b.team, fpath, fcaption, &b.channel)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send regular message
 | 
			
		||||
	resp, err := b.kbc.SendMessageByTeamName(b.team, msg.Username+msg.Text, &b.channel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return strconv.Itoa(resp.Result.MsgID), err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -291,7 +291,8 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, channel string, fi *conf
 | 
			
		||||
	content := bytes.NewReader(*fi.Data)
 | 
			
		||||
	sp := strings.Split(fi.Name, ".")
 | 
			
		||||
	mtype := mime.TypeByExtension("." + sp[len(sp)-1])
 | 
			
		||||
	if !strings.Contains(mtype, "image") && !strings.Contains(mtype, "video") {
 | 
			
		||||
	if !(strings.Contains(mtype, "image") || strings.Contains(mtype, "video") ||
 | 
			
		||||
		strings.Contains(mtype, "application") || strings.Contains(mtype, "audio")) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if fi.Comment != "" {
 | 
			
		||||
@@ -326,6 +327,18 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, channel string, fi *conf
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Errorf("sendImage failed: %#v", err)
 | 
			
		||||
		}
 | 
			
		||||
	case strings.Contains(mtype, "application"):
 | 
			
		||||
		b.Log.Debugf("sendFile %s", res.ContentURI)
 | 
			
		||||
		_, err = b.mc.SendFile(channel, fi.Name, res.ContentURI, mtype, uint(len(*fi.Data)))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Errorf("sendFile failed: %#v", err)
 | 
			
		||||
		}
 | 
			
		||||
	case strings.Contains(mtype, "audio"):
 | 
			
		||||
		b.Log.Debugf("sendAudio %s", res.ContentURI)
 | 
			
		||||
		_, err = b.mc.SendAudio(channel, fi.Name, res.ContentURI, mtype, uint(len(*fi.Data)))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Log.Errorf("sendAudio failed: %#v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	b.Log.Debugf("result: %#v", res)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,11 @@ func (b *Bmattermost) handleMatter() {
 | 
			
		||||
		} else {
 | 
			
		||||
			b.Log.Debugf("Choosing login/password based receiving")
 | 
			
		||||
		}
 | 
			
		||||
		// if for some reason we only want to sent stuff to mattermost but not receive, return
 | 
			
		||||
		if b.GetString("WebhookBindAddress") == "" && b.GetString("WebhookURL") != "" {
 | 
			
		||||
			b.Log.Debugf("No WebhookBindAddress specified, only WebhookURL. You will not receive messages from mattermost, only sending is possible.")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		go b.handleMatterClient(messages)
 | 
			
		||||
	}
 | 
			
		||||
	var ok bool
 | 
			
		||||
 
 | 
			
		||||
@@ -58,6 +58,9 @@ func (b *Brocketchat) doConnectWebhookURL() error {
 | 
			
		||||
func (b *Brocketchat) apiLogin() error {
 | 
			
		||||
	b.Log.Debugf("handling apiLogin()")
 | 
			
		||||
	credentials := &models.UserCredentials{Email: b.GetString("login"), Password: b.GetString("password")}
 | 
			
		||||
	if b.GetString("Token") != "" {
 | 
			
		||||
		credentials = &models.UserCredentials{ID: b.GetString("Login"), Token: b.GetString("Token")}
 | 
			
		||||
	}
 | 
			
		||||
	myURL, err := url.Parse(b.GetString("server"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ func (b *Bslack) handleSlack() {
 | 
			
		||||
			message.Text = b.replaceVariable(message.Text)
 | 
			
		||||
			message.Text = b.replaceChannel(message.Text)
 | 
			
		||||
			message.Text = b.replaceURL(message.Text)
 | 
			
		||||
			message.Text = b.replaceb0rkedMarkDown(message.Text)
 | 
			
		||||
			message.Text = html.UnescapeString(message.Text)
 | 
			
		||||
 | 
			
		||||
			// Add the avatar
 | 
			
		||||
@@ -43,7 +44,7 @@ func (b *Bslack) handleSlack() {
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) handleSlackClient(messages chan *config.Message) {
 | 
			
		||||
	for msg := range b.rtm.IncomingEvents {
 | 
			
		||||
		if msg.Type != sUserTyping && msg.Type != sLatencyReport {
 | 
			
		||||
		if msg.Type != sUserTyping && msg.Type != sHello && msg.Type != sLatencyReport {
 | 
			
		||||
			b.Log.Debugf("== Receiving event %#v", msg.Data)
 | 
			
		||||
		}
 | 
			
		||||
		switch ev := msg.Data.(type) {
 | 
			
		||||
@@ -86,7 +87,7 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
 | 
			
		||||
			b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj)
 | 
			
		||||
		case *slack.MemberJoinedChannelEvent:
 | 
			
		||||
			b.users.populateUser(ev.User)
 | 
			
		||||
		case *slack.LatencyReport:
 | 
			
		||||
		case *slack.HelloEvent, *slack.LatencyReport:
 | 
			
		||||
			continue
 | 
			
		||||
		default:
 | 
			
		||||
			b.Log.Debugf("Unhandled incoming event: %T", ev)
 | 
			
		||||
 
 | 
			
		||||
@@ -188,6 +188,36 @@ func (b *Bslack) replaceURL(text string) string {
 | 
			
		||||
	return text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) replaceb0rkedMarkDown(text string) string {
 | 
			
		||||
	// taken from https://github.com/mattermost/mattermost-server/blob/master/app/slackimport.go
 | 
			
		||||
	//
 | 
			
		||||
	regexReplaceAllString := []struct {
 | 
			
		||||
		regex *regexp.Regexp
 | 
			
		||||
		rpl   string
 | 
			
		||||
	}{
 | 
			
		||||
		// bold
 | 
			
		||||
		{
 | 
			
		||||
			regexp.MustCompile(`(^|[\s.;,])\*(\S[^*\n]+)\*`),
 | 
			
		||||
			"$1**$2**",
 | 
			
		||||
		},
 | 
			
		||||
		// strikethrough
 | 
			
		||||
		{
 | 
			
		||||
			regexp.MustCompile(`(^|[\s.;,])\~(\S[^~\n]+)\~`),
 | 
			
		||||
			"$1~~$2~~",
 | 
			
		||||
		},
 | 
			
		||||
		// single paragraph blockquote
 | 
			
		||||
		// Slack converts > character to >
 | 
			
		||||
		{
 | 
			
		||||
			regexp.MustCompile(`(?sm)^>`),
 | 
			
		||||
			">",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, rule := range regexReplaceAllString {
 | 
			
		||||
		text = rule.regex.ReplaceAllString(text, rule.rpl)
 | 
			
		||||
	}
 | 
			
		||||
	return text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) replaceCodeFence(text string) string {
 | 
			
		||||
	return codeFenceRE.ReplaceAllString(text, "```")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import (
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/helper"
 | 
			
		||||
	"github.com/42wim/matterbridge/matterhook"
 | 
			
		||||
	"github.com/hashicorp/golang-lru"
 | 
			
		||||
	lru "github.com/hashicorp/golang-lru"
 | 
			
		||||
	"github.com/nlopes/slack"
 | 
			
		||||
	"github.com/rs/xid"
 | 
			
		||||
)
 | 
			
		||||
@@ -36,6 +36,7 @@ type Bslack struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	sHello           = "hello"
 | 
			
		||||
	sChannelJoin     = "channel_join"
 | 
			
		||||
	sChannelLeave    = "channel_leave"
 | 
			
		||||
	sChannelJoined   = "channel_joined"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										47
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,3 +1,47 @@
 | 
			
		||||
# v1.16.2
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
 | 
			
		||||
- keybase: Add support for receiving attachments (keybase) (#923)
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
 | 
			
		||||
- general: Switch to new emoji library kyokomi/emoji (#948)
 | 
			
		||||
- general: Update markdown parsing library to github.com/gomarkdown/markdown (#944)
 | 
			
		||||
- ssh-chat: Update shazow/ssh-chat dependency (#947)
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
 | 
			
		||||
- slack: Fix issues with the slack block kit API #937 (#943).
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@42wim, @bmpickford, @goncalor
 | 
			
		||||
 | 
			
		||||
# v1.16.1
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
 | 
			
		||||
* rocketchat: add token support #892
 | 
			
		||||
* matrix: Add support for uploading application/x and audio/x (matrix). #929
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
 | 
			
		||||
* general: Do configuration validation on start-up. Fixes #888
 | 
			
		||||
* general: updated vendored libraries (discord/whatsapp) #932
 | 
			
		||||
* discord: user typing messages #914
 | 
			
		||||
* slack: Convert slack bold/strike to correct markdown (slack). Fixes #918
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
 | 
			
		||||
* discord: fix Failed to fetch information for members message. #894
 | 
			
		||||
* discord: remove obsolete file upload links (discord). #931
 | 
			
		||||
* slack: suppress unhandled HelloEvent message #913
 | 
			
		||||
* mattermost: Fix panic on WebhookURL only setting (mattermost). #917
 | 
			
		||||
* matrix: fix corrupted links between slack and matrix #924
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@qaisjp, @hramrach, @42wim
 | 
			
		||||
 | 
			
		||||
# v1.16.0
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
@@ -15,6 +59,9 @@
 | 
			
		||||
* xmpp: Fix possible panic at startup of the XMPP bridge #869
 | 
			
		||||
* mattermost: Make getChannelIdTeam behave like GetChannelId for groups (mattermost) #873
 | 
			
		||||
 | 
			
		||||
This release couldn't exist without the following contributors:
 | 
			
		||||
@hyperobject, @42wim, @bucko909, @MOZGIII
 | 
			
		||||
 | 
			
		||||
# v1.15.1
 | 
			
		||||
 | 
			
		||||
## New features
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -u -e -x -o pipefail
 | 
			
		||||
 | 
			
		||||
go version | grep go1.12 || exit
 | 
			
		||||
go version | grep go1.13 || exit
 | 
			
		||||
 | 
			
		||||
VERSION=$(git describe --tags)
 | 
			
		||||
mkdir ci/binaries
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ var (
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	UserTypingSupport = map[string]struct{}{
 | 
			
		||||
		"slack": {},
 | 
			
		||||
		"slack":   {},
 | 
			
		||||
		"discord": {},
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ import (
 | 
			
		||||
	"github.com/d5/tengo/script"
 | 
			
		||||
	"github.com/d5/tengo/stdlib"
 | 
			
		||||
	lru "github.com/hashicorp/golang-lru"
 | 
			
		||||
	"github.com/peterhellberg/emojilib"
 | 
			
		||||
	"github.com/matterbridge/emoji"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -85,6 +85,7 @@ func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string {
 | 
			
		||||
func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
 | 
			
		||||
	br := gw.Router.getBridge(cfg.Account)
 | 
			
		||||
	if br == nil {
 | 
			
		||||
		gw.checkConfig(cfg)
 | 
			
		||||
		br = bridge.New(cfg)
 | 
			
		||||
		br.Config = gw.Router.Config
 | 
			
		||||
		br.General = &gw.BridgeValues().General
 | 
			
		||||
@@ -104,6 +105,19 @@ func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gw *Gateway) checkConfig(cfg *config.Bridge) {
 | 
			
		||||
	match := false
 | 
			
		||||
	for _, key := range gw.Router.Config.Viper().AllKeys() {
 | 
			
		||||
		if strings.HasPrefix(key, cfg.Account) {
 | 
			
		||||
			match = true
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if !match {
 | 
			
		||||
		gw.logger.Fatalf("Account %s defined in gateway %s but no configuration found, exiting.", cfg.Account, gw.Name)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddConfig associates a new configuration with the gateway object.
 | 
			
		||||
func (gw *Gateway) AddConfig(cfg *config.Gateway) error {
 | 
			
		||||
	gw.Name = cfg.Name
 | 
			
		||||
@@ -358,7 +372,7 @@ func (gw *Gateway) modifyMessage(msg *config.Message) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// replace :emoji: to unicode
 | 
			
		||||
	msg.Text = emojilib.Replace(msg.Text)
 | 
			
		||||
	msg.Text = emoji.Sprint(msg.Text)
 | 
			
		||||
 | 
			
		||||
	br := gw.Bridges[msg.Account]
 | 
			
		||||
	// loop to replace messages
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,15 @@ import (
 | 
			
		||||
 | 
			
		||||
var testconfig = []byte(`
 | 
			
		||||
[irc.freenode]
 | 
			
		||||
server=""
 | 
			
		||||
[mattermost.test]
 | 
			
		||||
server=""
 | 
			
		||||
[gitter.42wim]
 | 
			
		||||
server=""
 | 
			
		||||
[discord.test]
 | 
			
		||||
server=""
 | 
			
		||||
[slack.test]
 | 
			
		||||
server=""
 | 
			
		||||
 | 
			
		||||
[[gateway]]
 | 
			
		||||
    name = "bridge1"
 | 
			
		||||
@@ -44,10 +49,15 @@ var testconfig = []byte(`
 | 
			
		||||
 | 
			
		||||
var testconfig2 = []byte(`
 | 
			
		||||
[irc.freenode]
 | 
			
		||||
server=""
 | 
			
		||||
[mattermost.test]
 | 
			
		||||
server=""
 | 
			
		||||
[gitter.42wim]
 | 
			
		||||
server=""
 | 
			
		||||
[discord.test]
 | 
			
		||||
server=""
 | 
			
		||||
[slack.test]
 | 
			
		||||
server=""
 | 
			
		||||
 | 
			
		||||
[[gateway]]
 | 
			
		||||
    name = "bridge1"
 | 
			
		||||
@@ -87,8 +97,11 @@ var testconfig2 = []byte(`
 | 
			
		||||
 | 
			
		||||
var testconfig3 = []byte(`
 | 
			
		||||
[irc.zzz]
 | 
			
		||||
server=""
 | 
			
		||||
[telegram.zzz]
 | 
			
		||||
server=""
 | 
			
		||||
[slack.zzz]
 | 
			
		||||
server=""
 | 
			
		||||
[[gateway]]
 | 
			
		||||
name="bridge"
 | 
			
		||||
enable=true
 | 
			
		||||
@@ -176,7 +189,6 @@ func TestNewRouter(t *testing.T) {
 | 
			
		||||
	assert.Equal(t, 1, len(r.Gateways))
 | 
			
		||||
	assert.Equal(t, 4, len(r.Gateways["bridge1"].Bridges))
 | 
			
		||||
	assert.Equal(t, 4, len(r.Gateways["bridge1"].Channels))
 | 
			
		||||
 | 
			
		||||
	r = maketestRouter(testconfig2)
 | 
			
		||||
	assert.Equal(t, 2, len(r.Gateways))
 | 
			
		||||
	assert.Equal(t, 4, len(r.Gateways["bridge1"].Bridges))
 | 
			
		||||
 
 | 
			
		||||
@@ -59,8 +59,14 @@ func NewRouter(rootLogger *logrus.Logger, cfg config.Config, bridgeMap map[strin
 | 
			
		||||
// between them.
 | 
			
		||||
func (r *Router) Start() error {
 | 
			
		||||
	m := make(map[string]*bridge.Bridge)
 | 
			
		||||
	if len(r.Gateways) == 0 {
 | 
			
		||||
		return fmt.Errorf("no [[gateway]] configured. See https://github.com/42wim/matterbridge/wiki/How-to-create-your-config for more info")
 | 
			
		||||
	}
 | 
			
		||||
	for _, gw := range r.Gateways {
 | 
			
		||||
		r.logger.Infof("Parsing gateway %s", gw.Name)
 | 
			
		||||
		if len(gw.Bridges) == 0 {
 | 
			
		||||
			return fmt.Errorf("no bridges configured for gateway %s. See https://github.com/42wim/matterbridge/wiki/How-to-create-your-config for more info", gw.Name)
 | 
			
		||||
		}
 | 
			
		||||
		for _, br := range gw.Bridges {
 | 
			
		||||
			m[br.Account] = br
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								go.mod
									
									
									
									
									
								
							@@ -5,13 +5,14 @@ require (
 | 
			
		||||
	github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
 | 
			
		||||
	github.com/Jeffail/gabs v1.1.1 // indirect
 | 
			
		||||
	github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0
 | 
			
		||||
	github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a
 | 
			
		||||
	github.com/Rhymen/go-whatsapp v0.0.3-0.20191003184814-fc3f792c814c
 | 
			
		||||
	github.com/bwmarrin/discordgo v0.19.0
 | 
			
		||||
	// github.com/bwmarrin/discordgo v0.19.0
 | 
			
		||||
	github.com/d5/tengo v1.24.3
 | 
			
		||||
	github.com/d5/tengo v1.24.8
 | 
			
		||||
	github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.4.7
 | 
			
		||||
	github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
 | 
			
		||||
	github.com/gomarkdown/markdown v0.0.0-20190912180731-281270bc6d83
 | 
			
		||||
	github.com/google/gops v0.3.6
 | 
			
		||||
	github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect
 | 
			
		||||
	github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f // indirect
 | 
			
		||||
@@ -25,8 +26,9 @@ require (
 | 
			
		||||
	github.com/labstack/echo/v4 v4.1.10
 | 
			
		||||
	github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
 | 
			
		||||
	github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d
 | 
			
		||||
	github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible
 | 
			
		||||
	github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91
 | 
			
		||||
	github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea
 | 
			
		||||
	github.com/matterbridge/gomatrix v0.0.0-20191026211822-6fc7accd00ca
 | 
			
		||||
	github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18
 | 
			
		||||
	github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61
 | 
			
		||||
	github.com/mattermost/mattermost-server v5.5.0+incompatible
 | 
			
		||||
@@ -36,16 +38,15 @@ require (
 | 
			
		||||
	github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
 | 
			
		||||
	github.com/nicksnyder/go-i18n v1.4.0 // indirect
 | 
			
		||||
	github.com/nlopes/slack v0.6.0
 | 
			
		||||
	//github.com/nlopes/slack v0.6.0
 | 
			
		||||
	github.com/onsi/ginkgo v1.6.0 // indirect
 | 
			
		||||
	github.com/onsi/gomega v1.4.1 // indirect
 | 
			
		||||
	github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
 | 
			
		||||
	github.com/pborman/uuid v0.0.0-20160216163710-c55201b03606 // indirect
 | 
			
		||||
	github.com/peterhellberg/emojilib v0.0.0-20190124112554-c18758d55320
 | 
			
		||||
	github.com/rs/xid v1.2.1
 | 
			
		||||
	github.com/russross/blackfriday v1.5.2
 | 
			
		||||
	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
 | 
			
		||||
	github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296
 | 
			
		||||
	github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
 | 
			
		||||
	github.com/shazow/ssh-chat v1.8.2
 | 
			
		||||
	github.com/sirupsen/logrus v1.4.2
 | 
			
		||||
	github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 // indirect
 | 
			
		||||
	github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect
 | 
			
		||||
@@ -54,24 +55,17 @@ require (
 | 
			
		||||
	github.com/technoweenie/multipartstreamer v1.0.1 // indirect
 | 
			
		||||
	github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
 | 
			
		||||
	github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2
 | 
			
		||||
	gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a // indirect
 | 
			
		||||
	gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179 // indirect
 | 
			
		||||
	gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f
 | 
			
		||||
	gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2 // indirect
 | 
			
		||||
	gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe // indirect
 | 
			
		||||
	gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 // indirect
 | 
			
		||||
	golang.org/x/image v0.0.0-20190902063713-cb417be4ba39
 | 
			
		||||
	golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect
 | 
			
		||||
	golang.org/x/text v0.3.2 // indirect
 | 
			
		||||
	gopkg.in/fsnotify.v1 v1.4.7 // indirect
 | 
			
		||||
	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
 | 
			
		||||
	gopkg.in/russross/blackfriday.v2 v2.0.1 // indirect
 | 
			
		||||
	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
replace github.com/bwmarrin/discordgo v0.19.0 => github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40
 | 
			
		||||
replace github.com/bwmarrin/discordgo v0.19.0 => github.com/matterbridge/discordgo v0.0.0-20191026232317-01823f4ebba4
 | 
			
		||||
 | 
			
		||||
replace gopkg.in/russross/blackfriday.v2 v2.0.1 => github.com/russross/blackfriday/v2 v2.0.1
 | 
			
		||||
replace github.com/nlopes/slack v0.6.0 => github.com/matterbridge/slack v0.1.1-0.20191113220225-25f80ef0a0d1
 | 
			
		||||
 | 
			
		||||
go 1.13
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								go.sum
									
									
									
									
									
								
							@@ -11,8 +11,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
 | 
			
		||||
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0 h1:TO7d4rocnNFng6ZQrPe7U6WqHtK5eHEMrgrnnM/72IQ=
 | 
			
		||||
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg=
 | 
			
		||||
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
 | 
			
		||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a h1:umvfZW+YE+ynhYwsyheyunB/3xRK68kNFMRNUMQxzJI=
 | 
			
		||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a/go.mod h1:qf/2PQi82Okxw/igghu/oMGzTeUYuKBq1JNo3tdQyNg=
 | 
			
		||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20191003184814-fc3f792c814c h1:+yAllLxP+WjpuVVE1WNm0/Oigbeob9+liYEyk/v4nj8=
 | 
			
		||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20191003184814-fc3f792c814c/go.mod h1:qf/2PQi82Okxw/igghu/oMGzTeUYuKBq1JNo3tdQyNg=
 | 
			
		||||
github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME=
 | 
			
		||||
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
 | 
			
		||||
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
 | 
			
		||||
@@ -21,6 +21,7 @@ github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e h1:IHXQQIpxASe3m
 | 
			
		||||
github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
 | 
			
		||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 | 
			
		||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 | 
			
		||||
github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58 h1:MkpmYfld/S8kXqTYI68DfL8/hHXjHogL120Dy00TIxc=
 | 
			
		||||
github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58/go.mod h1:YNfsMyWSs+h+PaYkxGeMVmVCX75Zj/pqdjbu12ciCYE=
 | 
			
		||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 | 
			
		||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 | 
			
		||||
@@ -32,8 +33,8 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
 | 
			
		||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 | 
			
		||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 | 
			
		||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 | 
			
		||||
github.com/d5/tengo v1.24.3 h1:wp44VW7fdfzMzIDT19tT5uNeGnm2UMd6s3TLAahrwSU=
 | 
			
		||||
github.com/d5/tengo v1.24.3/go.mod h1:VhLq8Q2QFhCIJO3NhvM934qOThykMqJi9y9Siqd1ocQ=
 | 
			
		||||
github.com/d5/tengo v1.24.8 h1:PRJ+NWt7ae/9sSbIfThOBTkPSvNV+dwYoBAvwfNgNJY=
 | 
			
		||||
github.com/d5/tengo v1.24.8/go.mod h1:VhLq8Q2QFhCIJO3NhvM934qOThykMqJi9y9Siqd1ocQ=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
@@ -63,6 +64,8 @@ github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk
 | 
			
		||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
 | 
			
		||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
 | 
			
		||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 | 
			
		||||
github.com/gomarkdown/markdown v0.0.0-20190912180731-281270bc6d83 h1:w5VNUHB0SP2tr1+boQJWKvnyn3P61UFErZ2e2ih6x0A=
 | 
			
		||||
github.com/gomarkdown/markdown v0.0.0-20190912180731-281270bc6d83/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
 | 
			
		||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 | 
			
		||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 | 
			
		||||
github.com/google/gops v0.3.6 h1:6akvbMlpZrEYOuoebn2kR+ZJekbZqJ28fJXTs84+8to=
 | 
			
		||||
@@ -88,7 +91,7 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
 | 
			
		||||
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
 | 
			
		||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 | 
			
		||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
			
		||||
github.com/jessevdk/go-flags v1.3.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 | 
			
		||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 | 
			
		||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 | 
			
		||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 h1:K//n/AqR5HjG3qxbrBCL4vJPW0MVFSs9CPK1OOJdRME=
 | 
			
		||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
 | 
			
		||||
@@ -121,16 +124,20 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe
 | 
			
		||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 | 
			
		||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d h1:F+Sr+C0ojSlYQ37BLylQtSFmyQULe3jbAygcyXQ9mVs=
 | 
			
		||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
 | 
			
		||||
github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40 h1:OJmjOa1ry5IZzFowLhAZ8b3bFPWFFNUbqGxs9pNqgEU=
 | 
			
		||||
github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
 | 
			
		||||
github.com/matterbridge/discordgo v0.0.0-20191026232317-01823f4ebba4 h1:RvH3lC4bEp+bieca+Yh5xPU8tLJgnk7ridiSwMFHrrw=
 | 
			
		||||
github.com/matterbridge/discordgo v0.0.0-20191026232317-01823f4ebba4/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
 | 
			
		||||
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI=
 | 
			
		||||
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible/go.mod h1:igE6rUAn3jai2wCdsjFHfhUoekjrFthoEjFObKKwSb4=
 | 
			
		||||
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 h1:KzDEcy8eDbTx881giW8a6llsAck3e2bJvMyKvh1IK+k=
 | 
			
		||||
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
 | 
			
		||||
github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea h1:kaADGqpK4gGO2BpzEyJrBxq2Jc57Rsar4i2EUxcACUc=
 | 
			
		||||
github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea/go.mod h1:+jWeaaUtXQbBRdKYWfjW6JDDYiI2XXE+3NnTjW5kg8g=
 | 
			
		||||
github.com/matterbridge/gomatrix v0.0.0-20191026211822-6fc7accd00ca h1:3ypqEpFpt6vg5Sv2xxA8/v4WiSOnWMXW7DqxTxpM4XI=
 | 
			
		||||
github.com/matterbridge/gomatrix v0.0.0-20191026211822-6fc7accd00ca/go.mod h1:+jWeaaUtXQbBRdKYWfjW6JDDYiI2XXE+3NnTjW5kg8g=
 | 
			
		||||
github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 h1:fLhwXtWGtfTgZVxHG1lcKjv+re7dRwyyuYFNu69xdho=
 | 
			
		||||
github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18/go.mod h1:yAjnZ34DuDyPHMPHHjOsTk/FefW4JJjoMMCGt/8uuQA=
 | 
			
		||||
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 h1:R/MgM/eUyRBQx2FiH6JVmXck8PaAuKfe2M1tWIzW7nE=
 | 
			
		||||
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61/go.mod h1:iXGEotOvwI1R1SjLxRc+BF5rUORTMtE0iMZBT2lxqAU=
 | 
			
		||||
github.com/matterbridge/slack v0.1.1-0.20191113220225-25f80ef0a0d1 h1:wXVBLvvMFMfqnDE6aVyxScanzRP1WIErz7+fY/9dhmY=
 | 
			
		||||
github.com/matterbridge/slack v0.1.1-0.20191113220225-25f80ef0a0d1/go.mod h1:2uCJim0Ct2z1Uj+XQq47KCLLC1b/9UTYaZOvDtbZfK4=
 | 
			
		||||
github.com/mattermost/mattermost-server v5.5.0+incompatible h1:0wcLGgYtd+YImtLDPf2AOfpBHxbU4suATx+6XKw1XbU=
 | 
			
		||||
github.com/mattermost/mattermost-server v5.5.0+incompatible/go.mod h1:5L6MjAec+XXQwMIt791Ganu45GKsSiM+I0tLR9wUj8Y=
 | 
			
		||||
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
 | 
			
		||||
@@ -157,8 +164,6 @@ github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 h1:mp6tU1r0xLostUGL
 | 
			
		||||
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9/go.mod h1:A5SRAcpTemjGgIuBq6Kic2yHcoeUFWUinOAlMP/i9xo=
 | 
			
		||||
github.com/nicksnyder/go-i18n v1.4.0 h1:AgLl+Yq7kg5OYlzCgu9cKTZOyI4tD/NgukKqLqC8E+I=
 | 
			
		||||
github.com/nicksnyder/go-i18n v1.4.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
 | 
			
		||||
github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
 | 
			
		||||
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
 | 
			
		||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 | 
			
		||||
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
 | 
			
		||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
			
		||||
@@ -170,8 +175,6 @@ github.com/pborman/uuid v0.0.0-20160216163710-c55201b03606 h1:/CPgDYrfeK2LMK6xcU
 | 
			
		||||
github.com/pborman/uuid v0.0.0-20160216163710-c55201b03606/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
 | 
			
		||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
 | 
			
		||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 | 
			
		||||
github.com/peterhellberg/emojilib v0.0.0-20190124112554-c18758d55320 h1:YxcQy/DV+48NGv1lxx1vsWBzs6W1f1ogubkuCozxpX0=
 | 
			
		||||
github.com/peterhellberg/emojilib v0.0.0-20190124112554-c18758d55320/go.mod h1:G7LufuPajuIvdt9OitkNt2qh0mmvD4bfRgRM7bhDIOA=
 | 
			
		||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 | 
			
		||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
@@ -191,20 +194,16 @@ github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
 | 
			
		||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
 | 
			
		||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
 | 
			
		||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 | 
			
		||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
 | 
			
		||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 | 
			
		||||
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
 | 
			
		||||
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
 | 
			
		||||
github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zKc9A3BuGYbQAGlEFyPuUA3jeMD0=
 | 
			
		||||
github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1/go.mod h1:vt2jWY/3Qw1bIzle5thrJWucsLuuX9iUNnp20CqCciI=
 | 
			
		||||
github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 h1:8RLq547MSVc6vhOuCl4Ca0TsAQknj6NX6ZLSZ3+xmio=
 | 
			
		||||
github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296/go.mod h1:1GLXsL4esywkpNId3v4QWuMf3THtWGitWvtQ/L3aSA4=
 | 
			
		||||
github.com/shazow/ssh-chat v1.8.2 h1:MMso9eWfCnPBelRsusYxKcRBUwHIPEQkR9WrO89II38=
 | 
			
		||||
github.com/shazow/ssh-chat v1.8.2/go.mod h1:cXTZK/D1zujEwB0y8DIT1GX8rIKjyLDYeWd+jitPX84=
 | 
			
		||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 h1:80VN+vGkqM773Br/uNNTSheo3KatTgV8IpjIKjvVLng=
 | 
			
		||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 | 
			
		||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U=
 | 
			
		||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
 | 
			
		||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
 | 
			
		||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 | 
			
		||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 | 
			
		||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 | 
			
		||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 | 
			
		||||
@@ -247,18 +246,6 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut
 | 
			
		||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 | 
			
		||||
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2 h1:UQwvu7FjUEdVYofx0U6bsc5odNE7wa5TSA0fl559GcA=
 | 
			
		||||
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2/go.mod h1:0MsIttMJIF/8Y7x0XjonJP7K99t3sR6bjj4m5S4JmqU=
 | 
			
		||||
gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a h1:Ax7kdHNICZiIeFpmevmaEWb0Ae3BUj3zCTKhZHZ+zd0=
 | 
			
		||||
gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a/go.mod h1:JT4uoTz0tfPoyVH88GZoWDNm5NHJI2VbUW+eyPClueI=
 | 
			
		||||
gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179 h1:rbON2KwBnWuFMlSHM8LELLlwroDRZw6xv0e6il6e5dk=
 | 
			
		||||
gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179/go.mod h1:Gn+LZmCrhPECMD3SOKlE+BOHwhOYD9j7WT9NUtkCrC8=
 | 
			
		||||
gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f h1:jwXy/CsM4xS2aoiF2fHAlukmInWhd2TlWB+HDCyvzKc=
 | 
			
		||||
gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f/go.mod h1:SIHlEr9462fpIfTrVWf3GqQDxnA65Vm3BMMsUtuA6W0=
 | 
			
		||||
gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2 h1:wD/sPUgx2QJFPTyXZpJnLaROolfeKuruh06U4pRV0WY=
 | 
			
		||||
gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2/go.mod h1:wQk4rLkWrdOPjUAtqJRJ10hIlseLSVYWP95PLrjDF9s=
 | 
			
		||||
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe h1:5kUPFAF52umOUPH12MuNUmyVTseJRNBftDl/KfsvX3I=
 | 
			
		||||
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe/go.mod h1:P9LSM1KVzrIstFgUaveuwiAm8PK5VTB3yJEU8kqlbrU=
 | 
			
		||||
gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638 h1:uPZaMiz6Sz0PZs3IZJWpU5qHKGNy///1pacZC9txiUI=
 | 
			
		||||
gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638/go.mod h1:EGRJaqe2eO9XGmFtQCvV3Lm9NLico3UhFwUpCG/+mVU=
 | 
			
		||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 | 
			
		||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
 | 
			
		||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 | 
			
		||||
@@ -266,11 +253,13 @@ go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
 | 
			
		||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 | 
			
		||||
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
 | 
			
		||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 | 
			
		||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
			
		||||
@@ -299,6 +288,7 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
 | 
			
		||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	version = "1.16.0"
 | 
			
		||||
	version = "1.16.2"
 | 
			
		||||
	githash string
 | 
			
		||||
 | 
			
		||||
	flagConfig  = flag.String("conf", "matterbridge.toml", "config file")
 | 
			
		||||
 
 | 
			
		||||
@@ -956,6 +956,11 @@ Server="https://yourrocketchatserver.domain.com:443"
 | 
			
		||||
#REQUIRED (when not using webhooks)
 | 
			
		||||
Login="yourlogin@domain.com"
 | 
			
		||||
Password="yourpass"
 | 
			
		||||
# When using access token set Login to the User ID associated with your token and Token to your token.
 | 
			
		||||
# When Token is set Password is ignored.
 | 
			
		||||
# Login="yOurUSerID"
 | 
			
		||||
# Token="YoUrUsER_toKEN"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### Settings for webhook matterbridge.
 | 
			
		||||
#USE DEDICATED BOT USER WHEN POSSIBLE! This allows you to use advanced features like message editing/deleting and uploads
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4699
									
								
								vendor/github.com/Rhymen/go-whatsapp/binary/proto/def.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4699
									
								
								vendor/github.com/Rhymen/go-whatsapp/binary/proto/def.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										389
									
								
								vendor/github.com/Rhymen/go-whatsapp/binary/proto/def.proto
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										389
									
								
								vendor/github.com/Rhymen/go-whatsapp/binary/proto/def.proto
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,22 +1,94 @@
 | 
			
		||||
syntax = "proto2";
 | 
			
		||||
package proto;
 | 
			
		||||
 | 
			
		||||
message FingerprintData {
 | 
			
		||||
    optional string publicKey = 1;
 | 
			
		||||
    optional string identifier = 2;
 | 
			
		||||
message HydratedQuickReplyButton {
 | 
			
		||||
    optional string displayText = 1;
 | 
			
		||||
    optional string buttonId = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message CombinedFingerprint {
 | 
			
		||||
    optional uint32 version = 1;
 | 
			
		||||
    optional FingerprintData localFingerprint = 2;
 | 
			
		||||
    optional FingerprintData remoteFingerprint = 3;
 | 
			
		||||
message HydratedURLButton {
 | 
			
		||||
    optional string displayText = 1;
 | 
			
		||||
    optional string url = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message MessageKey {
 | 
			
		||||
    optional string remoteJid = 1;
 | 
			
		||||
    optional bool fromMe = 2;
 | 
			
		||||
    optional string id = 3;
 | 
			
		||||
    optional string participant = 4;
 | 
			
		||||
message HydratedCallButton {
 | 
			
		||||
    optional string displayText = 1;
 | 
			
		||||
    optional string phoneNumber = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message HydratedTemplateButton {
 | 
			
		||||
    oneof hydratedButton {
 | 
			
		||||
        HydratedQuickReplyButton quickReplyButton = 1;
 | 
			
		||||
        HydratedURLButton urlButton = 2;
 | 
			
		||||
        HydratedCallButton callButton = 3;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message QuickReplyButton {
 | 
			
		||||
    optional HighlyStructuredMessage displayText = 1;
 | 
			
		||||
    optional string buttonId = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message URLButton {
 | 
			
		||||
    optional HighlyStructuredMessage displayText = 1;
 | 
			
		||||
    optional HighlyStructuredMessage url = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message CallButton {
 | 
			
		||||
    optional HighlyStructuredMessage displayText = 1;
 | 
			
		||||
    optional HighlyStructuredMessage phoneNumber = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message TemplateButton {
 | 
			
		||||
    oneof button {
 | 
			
		||||
        QuickReplyButton quickReplyButton = 1;
 | 
			
		||||
        URLButton urlButton = 2;
 | 
			
		||||
        CallButton callButton = 3;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Location {
 | 
			
		||||
    optional double degreesLatitude = 1;
 | 
			
		||||
    optional double degreesLongitude = 2;
 | 
			
		||||
    optional string name = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Point {
 | 
			
		||||
    optional double x = 3;
 | 
			
		||||
    optional double y = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message InteractiveAnnotation {
 | 
			
		||||
    repeated Point polygonVertices = 1;
 | 
			
		||||
    oneof action {
 | 
			
		||||
        Location location = 2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message AdReplyInfo {
 | 
			
		||||
    optional string advertiserName = 1;
 | 
			
		||||
    enum AD_REPLY_INFO_MEDIATYPE {
 | 
			
		||||
        NONE = 0;
 | 
			
		||||
        IMAGE = 1;
 | 
			
		||||
        VIDEO = 2;
 | 
			
		||||
    }
 | 
			
		||||
    optional AD_REPLY_INFO_MEDIATYPE mediaType = 2;
 | 
			
		||||
    optional bytes jpegThumbnail = 16;
 | 
			
		||||
    optional string caption = 17;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ContextInfo {
 | 
			
		||||
    optional string stanzaId = 1;
 | 
			
		||||
    optional string participant = 2;
 | 
			
		||||
    optional Message quotedMessage = 3;
 | 
			
		||||
    optional string remoteJid = 4;
 | 
			
		||||
    repeated string mentionedJid = 15;
 | 
			
		||||
    optional string conversionSource = 18;
 | 
			
		||||
    optional bytes conversionData = 19;
 | 
			
		||||
    optional uint32 conversionDelaySeconds = 20;
 | 
			
		||||
    optional uint32 forwardingScore = 21;
 | 
			
		||||
    optional bool isForwarded = 22;
 | 
			
		||||
    optional AdReplyInfo quotedAd = 23;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message SenderKeyDistributionMessage {
 | 
			
		||||
@@ -36,10 +108,12 @@ message ImageMessage {
 | 
			
		||||
    optional bytes fileEncSha256 = 9;
 | 
			
		||||
    repeated InteractiveAnnotation interactiveAnnotations = 10;
 | 
			
		||||
    optional string directPath = 11;
 | 
			
		||||
    optional int64 mediaKeyTimestamp = 12;
 | 
			
		||||
    optional bytes jpegThumbnail = 16;
 | 
			
		||||
    optional ContextInfo contextInfo = 17;
 | 
			
		||||
    optional bytes firstScanSidecar = 18;
 | 
			
		||||
    optional uint32 firstScanLength = 19;
 | 
			
		||||
    optional uint32 experimentGroupId = 20;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ContactMessage {
 | 
			
		||||
@@ -66,7 +140,7 @@ message ExtendedTextMessage {
 | 
			
		||||
    optional string title = 6;
 | 
			
		||||
    optional fixed32 textArgb = 7;
 | 
			
		||||
    optional fixed32 backgroundArgb = 8;
 | 
			
		||||
    enum FONTTYPE {
 | 
			
		||||
    enum EXTENDED_TEXT_MESSAGE_FONTTYPE {
 | 
			
		||||
        SANS_SERIF = 0;
 | 
			
		||||
        SERIF = 1;
 | 
			
		||||
        NORICAN_REGULAR = 2;
 | 
			
		||||
@@ -74,7 +148,12 @@ message ExtendedTextMessage {
 | 
			
		||||
        BEBASNEUE_REGULAR = 4;
 | 
			
		||||
        OSWALD_HEAVY = 5;
 | 
			
		||||
    }
 | 
			
		||||
    optional FONTTYPE font = 9;
 | 
			
		||||
    optional EXTENDED_TEXT_MESSAGE_FONTTYPE font = 9;
 | 
			
		||||
    enum EXTENDED_TEXT_MESSAGE_PREVIEWTYPE {
 | 
			
		||||
        NONE = 0;
 | 
			
		||||
        VIDEO = 1;
 | 
			
		||||
    }
 | 
			
		||||
    optional EXTENDED_TEXT_MESSAGE_PREVIEWTYPE previewType = 10;
 | 
			
		||||
    optional bytes jpegThumbnail = 16;
 | 
			
		||||
    optional ContextInfo contextInfo = 17;
 | 
			
		||||
}
 | 
			
		||||
@@ -90,6 +169,7 @@ message DocumentMessage {
 | 
			
		||||
    optional string fileName = 8;
 | 
			
		||||
    optional bytes fileEncSha256 = 9;
 | 
			
		||||
    optional string directPath = 10;
 | 
			
		||||
    optional int64 mediaKeyTimestamp = 11;
 | 
			
		||||
    optional bytes jpegThumbnail = 16;
 | 
			
		||||
    optional ContextInfo contextInfo = 17;
 | 
			
		||||
}
 | 
			
		||||
@@ -104,6 +184,7 @@ message AudioMessage {
 | 
			
		||||
    optional bytes mediaKey = 7;
 | 
			
		||||
    optional bytes fileEncSha256 = 8;
 | 
			
		||||
    optional string directPath = 9;
 | 
			
		||||
    optional int64 mediaKeyTimestamp = 10;
 | 
			
		||||
    optional ContextInfo contextInfo = 17;
 | 
			
		||||
    optional bytes streamingSidecar = 18;
 | 
			
		||||
}
 | 
			
		||||
@@ -122,15 +203,16 @@ message VideoMessage {
 | 
			
		||||
    optional bytes fileEncSha256 = 11;
 | 
			
		||||
    repeated InteractiveAnnotation interactiveAnnotations = 12;
 | 
			
		||||
    optional string directPath = 13;
 | 
			
		||||
    optional int64 mediaKeyTimestamp = 14;
 | 
			
		||||
    optional bytes jpegThumbnail = 16;
 | 
			
		||||
    optional ContextInfo contextInfo = 17;
 | 
			
		||||
    optional bytes streamingSidecar = 18;
 | 
			
		||||
    enum ATTRIBUTION {
 | 
			
		||||
    enum VIDEO_MESSAGE_ATTRIBUTION {
 | 
			
		||||
        NONE = 0;
 | 
			
		||||
        GIPHY = 1;
 | 
			
		||||
        TENOR = 2;
 | 
			
		||||
    }
 | 
			
		||||
    optional ATTRIBUTION gifAttribution = 19;
 | 
			
		||||
    optional VIDEO_MESSAGE_ATTRIBUTION gifAttribution = 19;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Call {
 | 
			
		||||
@@ -144,10 +226,10 @@ message Chat {
 | 
			
		||||
 | 
			
		||||
message ProtocolMessage {
 | 
			
		||||
    optional MessageKey key = 1;
 | 
			
		||||
    enum TYPE {
 | 
			
		||||
    enum PROTOCOL_MESSAGE_TYPE {
 | 
			
		||||
        REVOKE = 0;
 | 
			
		||||
    }
 | 
			
		||||
    optional TYPE type = 2;
 | 
			
		||||
    optional PROTOCOL_MESSAGE_TYPE type = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ContactsArrayMessage {
 | 
			
		||||
@@ -162,7 +244,7 @@ message HSMCurrency {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message HSMDateTimeComponent {
 | 
			
		||||
    enum DAYOFWEEKTYPE {
 | 
			
		||||
    enum HSM_DATE_TIME_COMPONENT_DAYOFWEEKTYPE {
 | 
			
		||||
        MONDAY = 1;
 | 
			
		||||
        TUESDAY = 2;
 | 
			
		||||
        WEDNESDAY = 3;
 | 
			
		||||
@@ -171,17 +253,17 @@ message HSMDateTimeComponent {
 | 
			
		||||
        SATURDAY = 6;
 | 
			
		||||
        SUNDAY = 7;
 | 
			
		||||
    }
 | 
			
		||||
    optional DAYOFWEEKTYPE dayOfWeek = 1;
 | 
			
		||||
    optional HSM_DATE_TIME_COMPONENT_DAYOFWEEKTYPE dayOfWeek = 1;
 | 
			
		||||
    optional uint32 year = 2;
 | 
			
		||||
    optional uint32 month = 3;
 | 
			
		||||
    optional uint32 dayOfMonth = 4;
 | 
			
		||||
    optional uint32 hour = 5;
 | 
			
		||||
    optional uint32 minute = 6;
 | 
			
		||||
    enum CALENDARTYPE {
 | 
			
		||||
    enum HSM_DATE_TIME_COMPONENT_CALENDARTYPE {
 | 
			
		||||
        GREGORIAN = 1;
 | 
			
		||||
        SOLAR_HIJRI = 2;
 | 
			
		||||
    }
 | 
			
		||||
    optional CALENDARTYPE calendar = 7;
 | 
			
		||||
    optional HSM_DATE_TIME_COMPONENT_CALENDARTYPE calendar = 7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message HSMDateTimeUnixEpoch {
 | 
			
		||||
@@ -210,17 +292,29 @@ message HighlyStructuredMessage {
 | 
			
		||||
    optional string fallbackLg = 4;
 | 
			
		||||
    optional string fallbackLc = 5;
 | 
			
		||||
    repeated HSMLocalizableParameter localizableParams = 6;
 | 
			
		||||
    optional string deterministicLg = 7;
 | 
			
		||||
    optional string deterministicLc = 8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message SendPaymentMessage {
 | 
			
		||||
    optional Message noteMessage = 2;
 | 
			
		||||
    optional MessageKey requestMessageKey = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message RequestPaymentMessage {
 | 
			
		||||
    optional Message noteMessage = 4;
 | 
			
		||||
    optional string currencyCodeIso4217 = 1;
 | 
			
		||||
    optional uint64 amount1000 = 2;
 | 
			
		||||
    optional string requestFrom = 3;
 | 
			
		||||
    optional Message noteMessage = 4;
 | 
			
		||||
    optional int64 expiryTimestamp = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message DeclinePaymentRequestMessage {
 | 
			
		||||
    optional MessageKey key = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message CancelPaymentRequestMessage {
 | 
			
		||||
    optional MessageKey key = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message LiveLocationMessage {
 | 
			
		||||
@@ -231,6 +325,7 @@ message LiveLocationMessage {
 | 
			
		||||
    optional uint32 degreesClockwiseFromMagneticNorth = 5;
 | 
			
		||||
    optional string caption = 6;
 | 
			
		||||
    optional int64 sequenceNumber = 7;
 | 
			
		||||
    optional uint32 timeOffset = 8;
 | 
			
		||||
    optional bytes jpegThumbnail = 16;
 | 
			
		||||
    optional ContextInfo contextInfo = 17;
 | 
			
		||||
}
 | 
			
		||||
@@ -245,10 +340,77 @@ message StickerMessage {
 | 
			
		||||
    optional uint32 width = 7;
 | 
			
		||||
    optional string directPath = 8;
 | 
			
		||||
    optional uint64 fileLength = 9;
 | 
			
		||||
    optional int64 mediaKeyTimestamp = 10;
 | 
			
		||||
    optional bytes pngThumbnail = 16;
 | 
			
		||||
    optional ContextInfo contextInfo = 17;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message FourRowTemplate {
 | 
			
		||||
    optional HighlyStructuredMessage content = 6;
 | 
			
		||||
    optional HighlyStructuredMessage footer = 7;
 | 
			
		||||
    repeated TemplateButton buttons = 8;
 | 
			
		||||
    oneof title {
 | 
			
		||||
        DocumentMessage documentMessage = 1;
 | 
			
		||||
        HighlyStructuredMessage highlyStructuredMessage = 2;
 | 
			
		||||
        ImageMessage imageMessage = 3;
 | 
			
		||||
        VideoMessage videoMessage = 4;
 | 
			
		||||
        LocationMessage locationMessage = 5;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message HydratedFourRowTemplate {
 | 
			
		||||
    optional string hydratedContentText = 6;
 | 
			
		||||
    optional string hydratedFooterText = 7;
 | 
			
		||||
    repeated HydratedTemplateButton hydratedButtons = 9;
 | 
			
		||||
    oneof title {
 | 
			
		||||
        DocumentMessage documentMessage = 1;
 | 
			
		||||
        string hydratedTitleText = 2;
 | 
			
		||||
        ImageMessage imageMessage = 3;
 | 
			
		||||
        VideoMessage videoMessage = 4;
 | 
			
		||||
        LocationMessage locationMessage = 5;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message TemplateMessage {
 | 
			
		||||
    oneof format {
 | 
			
		||||
        FourRowTemplate fourRowTemplate = 1;
 | 
			
		||||
        HydratedFourRowTemplate hydratedFourRowTemplate = 2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message TemplateButtonReplyMessage {
 | 
			
		||||
    optional string selectedButtonId = 1;
 | 
			
		||||
    repeated string selectedButtonDisplayText = 2;
 | 
			
		||||
    optional ContextInfo contextInfo = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ProductSnapshot {
 | 
			
		||||
    optional ImageMessage productImage = 1;
 | 
			
		||||
    optional string productId = 2;
 | 
			
		||||
    optional string title = 3;
 | 
			
		||||
    optional string description = 4;
 | 
			
		||||
    optional string currencyCode = 5;
 | 
			
		||||
    optional int64 priceAmount1000 = 6;
 | 
			
		||||
    optional string retailerId = 7;
 | 
			
		||||
    optional string url = 8;
 | 
			
		||||
    optional uint32 productImageCount = 9;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ProductMessage {
 | 
			
		||||
    optional ProductSnapshot product = 1;
 | 
			
		||||
    optional string businessOwnerJid = 2;
 | 
			
		||||
    optional ContextInfo contextInfo = 17;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message GroupInviteMessage {
 | 
			
		||||
    optional string groupJid = 1;
 | 
			
		||||
    optional string inviteCode = 2;
 | 
			
		||||
    optional int64 inviteExpiration = 3;
 | 
			
		||||
    optional string groupName = 4;
 | 
			
		||||
    optional bytes jpegThumbnail = 5;
 | 
			
		||||
    optional string caption = 6;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Message {
 | 
			
		||||
    optional string conversation = 1;
 | 
			
		||||
    optional SenderKeyDistributionMessage senderKeyDistributionMessage = 2;
 | 
			
		||||
@@ -266,47 +428,104 @@ message Message {
 | 
			
		||||
    optional HighlyStructuredMessage highlyStructuredMessage = 14;
 | 
			
		||||
    optional SenderKeyDistributionMessage fastRatchetKeySenderKeyDistributionMessage = 15;
 | 
			
		||||
    optional SendPaymentMessage sendPaymentMessage = 16;
 | 
			
		||||
    optional RequestPaymentMessage requestPaymentMessage = 17;
 | 
			
		||||
    optional LiveLocationMessage liveLocationMessage = 18;
 | 
			
		||||
    optional StickerMessage stickerMessage = 20;
 | 
			
		||||
    optional RequestPaymentMessage requestPaymentMessage = 22;
 | 
			
		||||
    optional DeclinePaymentRequestMessage declinePaymentRequestMessage = 23;
 | 
			
		||||
    optional CancelPaymentRequestMessage cancelPaymentRequestMessage = 24;
 | 
			
		||||
    optional TemplateMessage templateMessage = 25;
 | 
			
		||||
    optional StickerMessage stickerMessage = 26;
 | 
			
		||||
    optional ProductMessage productMessage = 27;
 | 
			
		||||
    optional GroupInviteMessage groupInviteMessage = 28;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ContextInfo {
 | 
			
		||||
    optional string stanzaId = 1;
 | 
			
		||||
    optional string participant = 2;
 | 
			
		||||
    repeated Message quotedMessage = 3;
 | 
			
		||||
    optional string remoteJid = 4;
 | 
			
		||||
    repeated string mentionedJid = 15;
 | 
			
		||||
    optional string conversionSource = 18;
 | 
			
		||||
    optional bytes conversionData = 19;
 | 
			
		||||
    optional uint32 conversionDelaySeconds = 20;
 | 
			
		||||
    optional bool isForwarded = 22;
 | 
			
		||||
    reserved 16, 17;
 | 
			
		||||
message MessageKey {
 | 
			
		||||
    optional string remoteJid = 1;
 | 
			
		||||
    optional bool fromMe = 2;
 | 
			
		||||
    optional string id = 3;
 | 
			
		||||
    optional string participant = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message InteractiveAnnotation {
 | 
			
		||||
    repeated Point polygonVertices = 1;
 | 
			
		||||
    oneof action {
 | 
			
		||||
        Location location = 2;
 | 
			
		||||
message WebFeatures {
 | 
			
		||||
    enum WEB_FEATURES_FLAG {
 | 
			
		||||
        NOT_IMPLEMENTED = 0;
 | 
			
		||||
        IMPLEMENTED = 1;
 | 
			
		||||
        OPTIONAL = 2;
 | 
			
		||||
    }
 | 
			
		||||
    optional WEB_FEATURES_FLAG labelsDisplay = 1;
 | 
			
		||||
    optional WEB_FEATURES_FLAG voipIndividualOutgoing = 2;
 | 
			
		||||
    optional WEB_FEATURES_FLAG groupsV3 = 3;
 | 
			
		||||
    optional WEB_FEATURES_FLAG groupsV3Create = 4;
 | 
			
		||||
    optional WEB_FEATURES_FLAG changeNumberV2 = 5;
 | 
			
		||||
    optional WEB_FEATURES_FLAG queryStatusV3Thumbnail = 6;
 | 
			
		||||
    optional WEB_FEATURES_FLAG liveLocations = 7;
 | 
			
		||||
    optional WEB_FEATURES_FLAG queryVname = 8;
 | 
			
		||||
    optional WEB_FEATURES_FLAG voipIndividualIncoming = 9;
 | 
			
		||||
    optional WEB_FEATURES_FLAG quickRepliesQuery = 10;
 | 
			
		||||
    optional WEB_FEATURES_FLAG payments = 11;
 | 
			
		||||
    optional WEB_FEATURES_FLAG stickerPackQuery = 12;
 | 
			
		||||
    optional WEB_FEATURES_FLAG liveLocationsFinal = 13;
 | 
			
		||||
    optional WEB_FEATURES_FLAG labelsEdit = 14;
 | 
			
		||||
    optional WEB_FEATURES_FLAG mediaUpload = 15;
 | 
			
		||||
    optional WEB_FEATURES_FLAG mediaUploadRichQuickReplies = 18;
 | 
			
		||||
    optional WEB_FEATURES_FLAG vnameV2 = 19;
 | 
			
		||||
    optional WEB_FEATURES_FLAG videoPlaybackUrl = 20;
 | 
			
		||||
    optional WEB_FEATURES_FLAG statusRanking = 21;
 | 
			
		||||
    optional WEB_FEATURES_FLAG voipIndividualVideo = 22;
 | 
			
		||||
    optional WEB_FEATURES_FLAG thirdPartyStickers = 23;
 | 
			
		||||
    optional WEB_FEATURES_FLAG frequentlyForwardedSetting = 24;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Point {
 | 
			
		||||
    optional double x = 3;
 | 
			
		||||
    optional double y = 4;
 | 
			
		||||
message TabletNotificationsInfo {
 | 
			
		||||
    optional uint64 timestamp = 2;
 | 
			
		||||
    optional uint32 unreadChats = 3;
 | 
			
		||||
    optional uint32 notifyMessageCount = 4;
 | 
			
		||||
    repeated NotificationMessageInfo notifyMessage = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Location {
 | 
			
		||||
    optional double degreesLatitude = 1;
 | 
			
		||||
    optional double degreesLongitude = 2;
 | 
			
		||||
    optional string name = 3;
 | 
			
		||||
message NotificationMessageInfo {
 | 
			
		||||
    optional MessageKey key = 1;
 | 
			
		||||
    optional Message message = 2;
 | 
			
		||||
    optional uint64 messageTimestamp = 3;
 | 
			
		||||
    optional string participant = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message WebNotificationsInfo {
 | 
			
		||||
    optional uint64 timestamp = 2;
 | 
			
		||||
    optional uint32 unreadChats = 3;
 | 
			
		||||
    optional uint32 notifyMessageCount = 4;
 | 
			
		||||
    repeated WebMessageInfo notifyMessages = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message PaymentInfo {
 | 
			
		||||
    optional uint64 amount1000 = 2;
 | 
			
		||||
    optional string receiverJid = 3;
 | 
			
		||||
    enum PAYMENT_INFO_STATUS {
 | 
			
		||||
        UNKNOWN_STATUS = 0;
 | 
			
		||||
        PROCESSING = 1;
 | 
			
		||||
        SENT = 2;
 | 
			
		||||
        NEED_TO_ACCEPT = 3;
 | 
			
		||||
        COMPLETE = 4;
 | 
			
		||||
        COULD_NOT_COMPLETE = 5;
 | 
			
		||||
        REFUNDED = 6;
 | 
			
		||||
        EXPIRED = 7;
 | 
			
		||||
        REJECTED = 8;
 | 
			
		||||
        CANCELLED = 9;
 | 
			
		||||
        WAITING_FOR_PAYER = 10;
 | 
			
		||||
        WAITING = 11;
 | 
			
		||||
    }
 | 
			
		||||
    optional PAYMENT_INFO_STATUS status = 4;
 | 
			
		||||
    optional uint64 transactionTimestamp = 5;
 | 
			
		||||
    optional MessageKey requestMessageKey = 6;
 | 
			
		||||
    optional uint64 expiryTimestamp = 7;
 | 
			
		||||
    optional bool futureproofed = 8;
 | 
			
		||||
    optional string currency = 9;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message WebMessageInfo {
 | 
			
		||||
    required MessageKey key = 1;
 | 
			
		||||
    optional Message message = 2;
 | 
			
		||||
    optional uint64 messageTimestamp = 3;
 | 
			
		||||
    enum STATUS {
 | 
			
		||||
    enum WEB_MESSAGE_INFO_STATUS {
 | 
			
		||||
        ERROR = 0;
 | 
			
		||||
        PENDING = 1;
 | 
			
		||||
        SERVER_ACK = 2;
 | 
			
		||||
@@ -314,7 +533,7 @@ message WebMessageInfo {
 | 
			
		||||
        READ = 4;
 | 
			
		||||
        PLAYED = 5;
 | 
			
		||||
    }
 | 
			
		||||
    optional STATUS status = 4 [default=PENDING];
 | 
			
		||||
    optional WEB_MESSAGE_INFO_STATUS status = 4;
 | 
			
		||||
    optional string participant = 5;
 | 
			
		||||
    optional bool ignore = 16;
 | 
			
		||||
    optional bool starred = 17;
 | 
			
		||||
@@ -324,7 +543,7 @@ message WebMessageInfo {
 | 
			
		||||
    optional bool multicast = 21;
 | 
			
		||||
    optional bool urlText = 22;
 | 
			
		||||
    optional bool urlNumber = 23;
 | 
			
		||||
    enum STUBTYPE {
 | 
			
		||||
    enum WEB_MESSAGE_INFO_STUBTYPE {
 | 
			
		||||
        UNKNOWN = 0;
 | 
			
		||||
        REVOKE = 1;
 | 
			
		||||
        CIPHERTEXT = 2;
 | 
			
		||||
@@ -369,49 +588,39 @@ message WebMessageInfo {
 | 
			
		||||
        CALL_MISSED_VIDEO = 41;
 | 
			
		||||
        INDIVIDUAL_CHANGE_NUMBER = 42;
 | 
			
		||||
        GROUP_DELETE = 43;
 | 
			
		||||
        GROUP_ANNOUNCE_MODE_MESSAGE_BOUNCE = 44;
 | 
			
		||||
        CALL_MISSED_GROUP_VOICE = 45;
 | 
			
		||||
        CALL_MISSED_GROUP_VIDEO = 46;
 | 
			
		||||
        PAYMENT_CIPHERTEXT = 47;
 | 
			
		||||
        PAYMENT_FUTUREPROOF = 48;
 | 
			
		||||
        PAYMENT_TRANSACTION_STATUS_UPDATE_FAILED = 49;
 | 
			
		||||
        PAYMENT_TRANSACTION_STATUS_UPDATE_REFUNDED = 50;
 | 
			
		||||
        PAYMENT_TRANSACTION_STATUS_UPDATE_REFUND_FAILED = 51;
 | 
			
		||||
        PAYMENT_TRANSACTION_STATUS_RECEIVER_PENDING_SETUP = 52;
 | 
			
		||||
        PAYMENT_TRANSACTION_STATUS_RECEIVER_SUCCESS_AFTER_HICCUP = 53;
 | 
			
		||||
        PAYMENT_ACTION_ACCOUNT_SETUP_REMINDER = 54;
 | 
			
		||||
        PAYMENT_ACTION_SEND_PAYMENT_REMINDER = 55;
 | 
			
		||||
        PAYMENT_ACTION_SEND_PAYMENT_INVITATION = 56;
 | 
			
		||||
        PAYMENT_ACTION_REQUEST_DECLINED = 57;
 | 
			
		||||
        PAYMENT_ACTION_REQUEST_EXPIRED = 58;
 | 
			
		||||
        PAYMENT_ACTION_REQUEST_CANCELLED = 59;
 | 
			
		||||
        BIZ_VERIFIED_TRANSITION_TOP_TO_BOTTOM = 60;
 | 
			
		||||
        BIZ_VERIFIED_TRANSITION_BOTTOM_TO_TOP = 61;
 | 
			
		||||
        BIZ_INTRO_TOP = 62;
 | 
			
		||||
        BIZ_INTRO_BOTTOM = 63;
 | 
			
		||||
        BIZ_NAME_CHANGE = 64;
 | 
			
		||||
        BIZ_MOVE_TO_CONSUMER_APP = 65;
 | 
			
		||||
        BIZ_TWO_TIER_MIGRATION_TOP = 66;
 | 
			
		||||
        BIZ_TWO_TIER_MIGRATION_BOTTOM = 67;
 | 
			
		||||
        OVERSIZED = 68;
 | 
			
		||||
        GROUP_CHANGE_NO_FREQUENTLY_FORWARDED = 69;
 | 
			
		||||
    }
 | 
			
		||||
    optional STUBTYPE messageStubType = 24;
 | 
			
		||||
    optional WEB_MESSAGE_INFO_STUBTYPE messageStubType = 24;
 | 
			
		||||
    optional bool clearMedia = 25;
 | 
			
		||||
    repeated string messageStubParameters = 26;
 | 
			
		||||
    optional uint32 duration = 27;
 | 
			
		||||
    repeated string labels = 28;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message WebNotificationsInfo {
 | 
			
		||||
    optional uint64 timestamp = 2;
 | 
			
		||||
    optional uint32 unreadChats = 3;
 | 
			
		||||
    optional uint32 notifyMessageCount = 4;
 | 
			
		||||
    repeated Message notifyMessages = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message NotificationMessageInfo {
 | 
			
		||||
    optional MessageKey key = 1;
 | 
			
		||||
    optional Message message = 2;
 | 
			
		||||
    optional uint64 messageTimestamp = 3;
 | 
			
		||||
    optional string participant = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message TabletNotificationsInfo {
 | 
			
		||||
    optional uint64 timestamp = 2;
 | 
			
		||||
    optional uint32 unreadChats = 3;
 | 
			
		||||
    optional uint32 notifyMessageCount = 4;
 | 
			
		||||
    repeated Message notifyMessage = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message WebFeatures {
 | 
			
		||||
    enum FLAG {
 | 
			
		||||
        NOT_IMPLEMENTED = 0;
 | 
			
		||||
        IMPLEMENTED = 1;
 | 
			
		||||
        OPTIONAL = 2;
 | 
			
		||||
    }
 | 
			
		||||
    optional FLAG labelsDisplay = 1;
 | 
			
		||||
    optional FLAG voipIndividualOutgoing = 2;
 | 
			
		||||
    optional FLAG groupsV3 = 3;
 | 
			
		||||
    optional FLAG groupsV3Create = 4;
 | 
			
		||||
    optional FLAG changeNumberV2 = 5;
 | 
			
		||||
    optional FLAG queryStatusV3Thumbnail = 6;
 | 
			
		||||
    optional FLAG liveLocations = 7;
 | 
			
		||||
    optional FLAG queryVname = 8;
 | 
			
		||||
    optional FLAG voipIndividualIncoming = 9;
 | 
			
		||||
    optional FLAG quickRepliesQuery = 10;
 | 
			
		||||
    optional PaymentInfo paymentInfo = 29;
 | 
			
		||||
    optional LiveLocationMessage finalLiveLocation = 30;
 | 
			
		||||
    optional PaymentInfo quotedPaymentInfo = 31;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/Rhymen/go-whatsapp/conn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/Rhymen/go-whatsapp/conn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,6 +4,7 @@ package whatsapp
 | 
			
		||||
import (
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@@ -91,6 +92,7 @@ type Conn struct {
 | 
			
		||||
	shortClientName string
 | 
			
		||||
 | 
			
		||||
	loginSessionLock sync.RWMutex
 | 
			
		||||
	Proxy            func(*http.Request) (*url.URL, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type websocketWrapper struct {
 | 
			
		||||
@@ -121,6 +123,21 @@ func NewConn(timeout time.Duration) (*Conn, error) {
 | 
			
		||||
	return wac, wac.connect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewConnWithProxy Create a new connect with a given timeout and a http proxy.
 | 
			
		||||
func NewConnWithProxy(timeout time.Duration, proxy func(*http.Request) (*url.URL, error)) (*Conn, error) {
 | 
			
		||||
	wac := &Conn{
 | 
			
		||||
		handler:    make([]Handler, 0),
 | 
			
		||||
		msgCount:   0,
 | 
			
		||||
		msgTimeout: timeout,
 | 
			
		||||
		Store:      newStore(),
 | 
			
		||||
 | 
			
		||||
		longClientName:  "github.com/rhymen/go-whatsapp",
 | 
			
		||||
		shortClientName: "go-whatsapp",
 | 
			
		||||
		Proxy:           proxy,
 | 
			
		||||
	}
 | 
			
		||||
	return wac, wac.connect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// connect should be guarded with wsWriteMutex
 | 
			
		||||
func (wac *Conn) connect() (err error) {
 | 
			
		||||
	if wac.connected {
 | 
			
		||||
@@ -137,6 +154,7 @@ func (wac *Conn) connect() (err error) {
 | 
			
		||||
		ReadBufferSize:   25 * 1024 * 1024,
 | 
			
		||||
		WriteBufferSize:  10 * 1024 * 1024,
 | 
			
		||||
		HandshakeTimeout: wac.msgTimeout,
 | 
			
		||||
		Proxy:            wac.Proxy,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	headers := http.Header{"Origin": []string{"https://web.whatsapp.com"}}
 | 
			
		||||
@@ -202,7 +220,7 @@ func (wac *Conn) AdminTest() (bool, error) {
 | 
			
		||||
		return false, ErrInvalidSession
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := wac.sendAdminTest()			
 | 
			
		||||
	result, err := wac.sendAdminTest()
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/github.com/Rhymen/go-whatsapp/contact.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/Rhymen/go-whatsapp/contact.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -51,6 +51,10 @@ func (wac *Conn) LoadMessagesAfter(jid, messageId string, count int) (*binary.No
 | 
			
		||||
	return wac.query("message", jid, messageId, "after", "true", "", count, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (wac *Conn) LoadMediaInfo(jid, messageId, owner string) (*binary.Node, error) {
 | 
			
		||||
	return wac.query("media", jid, messageId, "", owner, "", 0, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (wac *Conn) Presence(jid string, presence Presence) (<-chan string, error) {
 | 
			
		||||
	ts := time.Now().Unix()
 | 
			
		||||
	tag := fmt.Sprintf("%d.--%d", ts, wac.msgCount)
 | 
			
		||||
@@ -163,7 +167,12 @@ func (wac *Conn) query(t, jid, messageId, kind, owner, search string, count, pag
 | 
			
		||||
		n.Attributes["page"] = strconv.Itoa(page)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ch, err := wac.writeBinary(n, group, ignore, tag)
 | 
			
		||||
	metric := group
 | 
			
		||||
	if t == "media" {
 | 
			
		||||
		metric = queryMedia
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ch, err := wac.writeBinary(n, metric, ignore, tag)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/github.com/Rhymen/go-whatsapp/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/Rhymen/go-whatsapp/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,18 +6,20 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrAlreadyConnected       = errors.New("already connected")
 | 
			
		||||
	ErrAlreadyLoggedIn        = errors.New("already logged in")
 | 
			
		||||
	ErrInvalidSession         = errors.New("invalid session")
 | 
			
		||||
	ErrLoginInProgress        = errors.New("login or restore already running")
 | 
			
		||||
	ErrNotConnected           = errors.New("not connected")
 | 
			
		||||
	ErrInvalidWsData          = errors.New("received invalid data")
 | 
			
		||||
	ErrInvalidWsState         = errors.New("can't handle binary data when not logged in")
 | 
			
		||||
	ErrConnectionTimeout      = errors.New("connection timed out")
 | 
			
		||||
	ErrMissingMessageTag      = errors.New("no messageTag specified or to short")
 | 
			
		||||
	ErrInvalidHmac            = errors.New("invalid hmac")
 | 
			
		||||
	ErrInvalidServerResponse  = errors.New("invalid response received from server")
 | 
			
		||||
	ErrServerRespondedWith404 = errors.New("server responded with status 404")
 | 
			
		||||
	ErrAlreadyConnected           = errors.New("already connected")
 | 
			
		||||
	ErrAlreadyLoggedIn            = errors.New("already logged in")
 | 
			
		||||
	ErrInvalidSession             = errors.New("invalid session")
 | 
			
		||||
	ErrLoginInProgress            = errors.New("login or restore already running")
 | 
			
		||||
	ErrNotConnected               = errors.New("not connected")
 | 
			
		||||
	ErrInvalidWsData              = errors.New("received invalid data")
 | 
			
		||||
	ErrInvalidWsState             = errors.New("can't handle binary data when not logged in")
 | 
			
		||||
	ErrConnectionTimeout          = errors.New("connection timed out")
 | 
			
		||||
	ErrMissingMessageTag          = errors.New("no messageTag specified or to short")
 | 
			
		||||
	ErrInvalidHmac                = errors.New("invalid hmac")
 | 
			
		||||
	ErrInvalidServerResponse      = errors.New("invalid response received from server")
 | 
			
		||||
	ErrServerRespondedWith404     = errors.New("server responded with status 404")
 | 
			
		||||
	ErrMediaDownloadFailedWith404 = errors.New("download failed with status code 404")
 | 
			
		||||
	ErrMediaDownloadFailedWith410 = errors.New("download failed with status code 410")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ErrConnectionFailed struct {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/Rhymen/go-whatsapp/handler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/Rhymen/go-whatsapp/handler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -81,6 +81,14 @@ type LocationMessageHandler interface {
 | 
			
		||||
	HandleLocationMessage(message LocationMessage)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
The StickerMessageHandler interface needs to be implemented to receive location messages dispatched by the dispatcher.
 | 
			
		||||
*/
 | 
			
		||||
type StickerMessageHandler interface {
 | 
			
		||||
	Handler
 | 
			
		||||
	HandleStickerMessage(message StickerMessage)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
The JsonMessageHandler interface needs to be implemented to receive json messages dispatched by the dispatcher.
 | 
			
		||||
These json messages contain status updates of every kind sent by WhatsAppWeb servers. WhatsAppWeb uses these messages
 | 
			
		||||
@@ -247,6 +255,18 @@ func (wac *Conn) handleWithCustomHandlers(message interface{}, handlers []Handle
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case StickerMessage:
 | 
			
		||||
		for _, h := range handlers {
 | 
			
		||||
			if x, ok := h.(StickerMessageHandler); ok {
 | 
			
		||||
				if wac.shouldCallSynchronously(h) {
 | 
			
		||||
					x.HandleStickerMessage(m)
 | 
			
		||||
				} else {
 | 
			
		||||
					go x.HandleStickerMessage(m)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case *proto.WebMessageInfo:
 | 
			
		||||
		for _, h := range handlers {
 | 
			
		||||
			if x, ok := h.(RawMessageHandler); ok {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/Rhymen/go-whatsapp/media.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/Rhymen/go-whatsapp/media.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -74,6 +74,12 @@ func downloadMedia(url string) (file []byte, mac []byte, err error) {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if resp.StatusCode != 200 {
 | 
			
		||||
		if resp.StatusCode == 404 {
 | 
			
		||||
			return nil, nil, ErrMediaDownloadFailedWith404
 | 
			
		||||
		}
 | 
			
		||||
		if resp.StatusCode == 410 {
 | 
			
		||||
			return nil, nil, ErrMediaDownloadFailedWith410
 | 
			
		||||
		}
 | 
			
		||||
		return nil, nil, fmt.Errorf("download failed with status code %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										151
									
								
								vendor/github.com/Rhymen/go-whatsapp/message.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										151
									
								
								vendor/github.com/Rhymen/go-whatsapp/message.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,13 +4,14 @@ import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/Rhymen/go-whatsapp/binary"
 | 
			
		||||
	"github.com/Rhymen/go-whatsapp/binary/proto"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/Rhymen/go-whatsapp/binary"
 | 
			
		||||
	"github.com/Rhymen/go-whatsapp/binary/proto"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MediaType string
 | 
			
		||||
@@ -131,6 +132,7 @@ type MessageInfo struct {
 | 
			
		||||
	PushName        string
 | 
			
		||||
	Status          MessageStatus
 | 
			
		||||
	QuotedMessageID string
 | 
			
		||||
	QuotedMessage   proto.Message
 | 
			
		||||
 | 
			
		||||
	Source *proto.WebMessageInfo
 | 
			
		||||
}
 | 
			
		||||
@@ -170,7 +172,7 @@ func getInfoProto(info *MessageInfo) *proto.WebMessageInfo {
 | 
			
		||||
	}
 | 
			
		||||
	info.FromMe = true
 | 
			
		||||
 | 
			
		||||
	status := proto.WebMessageInfo_STATUS(info.Status)
 | 
			
		||||
	status := proto.WebMessageInfo_WEB_MESSAGE_INFO_STATUS(info.Status)
 | 
			
		||||
 | 
			
		||||
	return &proto.WebMessageInfo{
 | 
			
		||||
		Key: &proto.MessageKey{
 | 
			
		||||
@@ -183,6 +185,22 @@ func getInfoProto(info *MessageInfo) *proto.WebMessageInfo {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getContextInfoProto(info *MessageInfo) *proto.ContextInfo {
 | 
			
		||||
	if len(info.QuotedMessageID) > 0 {
 | 
			
		||||
		contextInfo := &proto.ContextInfo{
 | 
			
		||||
			StanzaId: &info.QuotedMessageID,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if &info.QuotedMessage != nil {
 | 
			
		||||
			contextInfo.QuotedMessage = &info.QuotedMessage
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return contextInfo
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
TextMessage represents a text message.
 | 
			
		||||
*/
 | 
			
		||||
@@ -204,9 +222,21 @@ func getTextMessage(msg *proto.WebMessageInfo) TextMessage {
 | 
			
		||||
 | 
			
		||||
func getTextProto(msg TextMessage) *proto.WebMessageInfo {
 | 
			
		||||
	p := getInfoProto(&msg.Info)
 | 
			
		||||
	p.Message = &proto.Message{
 | 
			
		||||
		Conversation: &msg.Text,
 | 
			
		||||
	contextInfo := getContextInfoProto(&msg.Info)
 | 
			
		||||
 | 
			
		||||
	if contextInfo == nil {
 | 
			
		||||
		p.Message = &proto.Message{
 | 
			
		||||
			Conversation: &msg.Text,
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		p.Message = &proto.Message{
 | 
			
		||||
			ExtendedTextMessage: &proto.ExtendedTextMessage{
 | 
			
		||||
				Text:        &msg.Text,
 | 
			
		||||
				ContextInfo: contextInfo,
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -229,7 +259,8 @@ type ImageMessage struct {
 | 
			
		||||
 | 
			
		||||
func getImageMessage(msg *proto.WebMessageInfo) ImageMessage {
 | 
			
		||||
	image := msg.GetMessage().GetImageMessage()
 | 
			
		||||
	return ImageMessage{
 | 
			
		||||
 | 
			
		||||
	imageMessage := ImageMessage{
 | 
			
		||||
		Info:          getMessageInfo(msg),
 | 
			
		||||
		Caption:       image.GetCaption(),
 | 
			
		||||
		Thumbnail:     image.GetJpegThumbnail(),
 | 
			
		||||
@@ -240,10 +271,18 @@ func getImageMessage(msg *proto.WebMessageInfo) ImageMessage {
 | 
			
		||||
		fileSha256:    image.GetFileSha256(),
 | 
			
		||||
		fileLength:    image.GetFileLength(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if contextInfo := image.GetContextInfo(); contextInfo != nil {
 | 
			
		||||
		imageMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return imageMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getImageProto(msg ImageMessage) *proto.WebMessageInfo {
 | 
			
		||||
	p := getInfoProto(&msg.Info)
 | 
			
		||||
	contextInfo := getContextInfoProto(&msg.Info)
 | 
			
		||||
 | 
			
		||||
	p.Message = &proto.Message{
 | 
			
		||||
		ImageMessage: &proto.ImageMessage{
 | 
			
		||||
			Caption:       &msg.Caption,
 | 
			
		||||
@@ -254,6 +293,7 @@ func getImageProto(msg ImageMessage) *proto.WebMessageInfo {
 | 
			
		||||
			FileEncSha256: msg.fileEncSha256,
 | 
			
		||||
			FileSha256:    msg.fileSha256,
 | 
			
		||||
			FileLength:    &msg.fileLength,
 | 
			
		||||
			ContextInfo:   contextInfo,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
@@ -287,7 +327,8 @@ type VideoMessage struct {
 | 
			
		||||
 | 
			
		||||
func getVideoMessage(msg *proto.WebMessageInfo) VideoMessage {
 | 
			
		||||
	vid := msg.GetMessage().GetVideoMessage()
 | 
			
		||||
	return VideoMessage{
 | 
			
		||||
 | 
			
		||||
	videoMessage := VideoMessage{
 | 
			
		||||
		Info:          getMessageInfo(msg),
 | 
			
		||||
		Caption:       vid.GetCaption(),
 | 
			
		||||
		Thumbnail:     vid.GetJpegThumbnail(),
 | 
			
		||||
@@ -300,10 +341,18 @@ func getVideoMessage(msg *proto.WebMessageInfo) VideoMessage {
 | 
			
		||||
		fileSha256:    vid.GetFileSha256(),
 | 
			
		||||
		fileLength:    vid.GetFileLength(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if contextInfo := vid.GetContextInfo(); contextInfo != nil {
 | 
			
		||||
		videoMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return videoMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getVideoProto(msg VideoMessage) *proto.WebMessageInfo {
 | 
			
		||||
	p := getInfoProto(&msg.Info)
 | 
			
		||||
	contextInfo := getContextInfoProto(&msg.Info)
 | 
			
		||||
 | 
			
		||||
	p.Message = &proto.Message{
 | 
			
		||||
		VideoMessage: &proto.VideoMessage{
 | 
			
		||||
			Caption:       &msg.Caption,
 | 
			
		||||
@@ -316,6 +365,7 @@ func getVideoProto(msg VideoMessage) *proto.WebMessageInfo {
 | 
			
		||||
			FileSha256:    msg.fileSha256,
 | 
			
		||||
			FileLength:    &msg.fileLength,
 | 
			
		||||
			Mimetype:      &msg.Type,
 | 
			
		||||
			ContextInfo:   contextInfo,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
@@ -337,6 +387,7 @@ type AudioMessage struct {
 | 
			
		||||
	Length        uint32
 | 
			
		||||
	Type          string
 | 
			
		||||
	Content       io.Reader
 | 
			
		||||
	Ptt           bool
 | 
			
		||||
	url           string
 | 
			
		||||
	mediaKey      []byte
 | 
			
		||||
	fileEncSha256 []byte
 | 
			
		||||
@@ -346,7 +397,8 @@ type AudioMessage struct {
 | 
			
		||||
 | 
			
		||||
func getAudioMessage(msg *proto.WebMessageInfo) AudioMessage {
 | 
			
		||||
	aud := msg.GetMessage().GetAudioMessage()
 | 
			
		||||
	return AudioMessage{
 | 
			
		||||
 | 
			
		||||
	audioMessage := AudioMessage{
 | 
			
		||||
		Info:          getMessageInfo(msg),
 | 
			
		||||
		url:           aud.GetUrl(),
 | 
			
		||||
		mediaKey:      aud.GetMediaKey(),
 | 
			
		||||
@@ -356,10 +408,17 @@ func getAudioMessage(msg *proto.WebMessageInfo) AudioMessage {
 | 
			
		||||
		fileSha256:    aud.GetFileSha256(),
 | 
			
		||||
		fileLength:    aud.GetFileLength(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if contextInfo := aud.GetContextInfo(); contextInfo != nil {
 | 
			
		||||
		audioMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return audioMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAudioProto(msg AudioMessage) *proto.WebMessageInfo {
 | 
			
		||||
	p := getInfoProto(&msg.Info)
 | 
			
		||||
	contextInfo := getContextInfoProto(&msg.Info)
 | 
			
		||||
	p.Message = &proto.Message{
 | 
			
		||||
		AudioMessage: &proto.AudioMessage{
 | 
			
		||||
			Url:           &msg.url,
 | 
			
		||||
@@ -369,6 +428,8 @@ func getAudioProto(msg AudioMessage) *proto.WebMessageInfo {
 | 
			
		||||
			FileSha256:    msg.fileSha256,
 | 
			
		||||
			FileLength:    &msg.fileLength,
 | 
			
		||||
			Mimetype:      &msg.Type,
 | 
			
		||||
			ContextInfo:   contextInfo,
 | 
			
		||||
			Ptt:           &msg.Ptt,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
@@ -402,7 +463,8 @@ type DocumentMessage struct {
 | 
			
		||||
 | 
			
		||||
func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage {
 | 
			
		||||
	doc := msg.GetMessage().GetDocumentMessage()
 | 
			
		||||
	return DocumentMessage{
 | 
			
		||||
 | 
			
		||||
	documentMessage := DocumentMessage{
 | 
			
		||||
		Info:          getMessageInfo(msg),
 | 
			
		||||
		Title:         doc.GetTitle(),
 | 
			
		||||
		PageCount:     doc.GetPageCount(),
 | 
			
		||||
@@ -415,10 +477,17 @@ func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage {
 | 
			
		||||
		fileSha256:    doc.GetFileSha256(),
 | 
			
		||||
		fileLength:    doc.GetFileLength(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if contextInfo := doc.GetContextInfo(); contextInfo != nil {
 | 
			
		||||
		documentMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return documentMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getDocumentProto(msg DocumentMessage) *proto.WebMessageInfo {
 | 
			
		||||
	p := getInfoProto(&msg.Info)
 | 
			
		||||
	contextInfo := getContextInfoProto(&msg.Info)
 | 
			
		||||
	p.Message = &proto.Message{
 | 
			
		||||
		DocumentMessage: &proto.DocumentMessage{
 | 
			
		||||
			JpegThumbnail: msg.Thumbnail,
 | 
			
		||||
@@ -430,6 +499,7 @@ func getDocumentProto(msg DocumentMessage) *proto.WebMessageInfo {
 | 
			
		||||
			PageCount:     &msg.PageCount,
 | 
			
		||||
			Title:         &msg.Title,
 | 
			
		||||
			Mimetype:      &msg.Type,
 | 
			
		||||
			ContextInfo:   contextInfo,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
@@ -457,7 +527,8 @@ type LocationMessage struct {
 | 
			
		||||
 | 
			
		||||
func GetLocationMessage(msg *proto.WebMessageInfo) LocationMessage {
 | 
			
		||||
	loc := msg.GetMessage().GetLocationMessage()
 | 
			
		||||
	return LocationMessage{
 | 
			
		||||
 | 
			
		||||
	locationMessage := LocationMessage{
 | 
			
		||||
		Info:             getMessageInfo(msg),
 | 
			
		||||
		DegreesLatitude:  loc.GetDegreesLatitude(),
 | 
			
		||||
		DegreesLongitude: loc.GetDegreesLongitude(),
 | 
			
		||||
@@ -466,10 +537,18 @@ func GetLocationMessage(msg *proto.WebMessageInfo) LocationMessage {
 | 
			
		||||
		Url:              loc.GetUrl(),
 | 
			
		||||
		JpegThumbnail:    loc.GetJpegThumbnail(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if contextInfo := loc.GetContextInfo(); contextInfo != nil {
 | 
			
		||||
		locationMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return locationMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetLocationProto(msg LocationMessage) *proto.WebMessageInfo {
 | 
			
		||||
	p := getInfoProto(&msg.Info)
 | 
			
		||||
	contextInfo := getContextInfoProto(&msg.Info)
 | 
			
		||||
 | 
			
		||||
	p.Message = &proto.Message{
 | 
			
		||||
		LocationMessage: &proto.LocationMessage{
 | 
			
		||||
			DegreesLatitude:  &msg.DegreesLatitude,
 | 
			
		||||
@@ -478,6 +557,7 @@ func GetLocationProto(msg LocationMessage) *proto.WebMessageInfo {
 | 
			
		||||
			Address:          &msg.Address,
 | 
			
		||||
			Url:              &msg.Url,
 | 
			
		||||
			JpegThumbnail:    msg.JpegThumbnail,
 | 
			
		||||
			ContextInfo:      contextInfo,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
@@ -500,7 +580,8 @@ type LiveLocationMessage struct {
 | 
			
		||||
 | 
			
		||||
func GetLiveLocationMessage(msg *proto.WebMessageInfo) LiveLocationMessage {
 | 
			
		||||
	loc := msg.GetMessage().GetLiveLocationMessage()
 | 
			
		||||
	return LiveLocationMessage{
 | 
			
		||||
 | 
			
		||||
	liveLocationMessage := LiveLocationMessage{
 | 
			
		||||
		Info:                              getMessageInfo(msg),
 | 
			
		||||
		DegreesLatitude:                   loc.GetDegreesLatitude(),
 | 
			
		||||
		DegreesLongitude:                  loc.GetDegreesLongitude(),
 | 
			
		||||
@@ -511,10 +592,17 @@ func GetLiveLocationMessage(msg *proto.WebMessageInfo) LiveLocationMessage {
 | 
			
		||||
		SequenceNumber:                    loc.GetSequenceNumber(),
 | 
			
		||||
		JpegThumbnail:                     loc.GetJpegThumbnail(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if contextInfo := loc.GetContextInfo(); contextInfo != nil {
 | 
			
		||||
		liveLocationMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return liveLocationMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetLiveLocationProto(msg LiveLocationMessage) *proto.WebMessageInfo {
 | 
			
		||||
	p := getInfoProto(&msg.Info)
 | 
			
		||||
	contextInfo := getContextInfoProto(&msg.Info)
 | 
			
		||||
	p.Message = &proto.Message{
 | 
			
		||||
		LiveLocationMessage: &proto.LiveLocationMessage{
 | 
			
		||||
			DegreesLatitude:                   &msg.DegreesLatitude,
 | 
			
		||||
@@ -525,11 +613,49 @@ func GetLiveLocationProto(msg LiveLocationMessage) *proto.WebMessageInfo {
 | 
			
		||||
			Caption:                           &msg.Caption,
 | 
			
		||||
			SequenceNumber:                    &msg.SequenceNumber,
 | 
			
		||||
			JpegThumbnail:                     msg.JpegThumbnail,
 | 
			
		||||
			ContextInfo:                       contextInfo,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
StickerMessage represents a sticker message.
 | 
			
		||||
*/
 | 
			
		||||
type StickerMessage struct {
 | 
			
		||||
	Info MessageInfo
 | 
			
		||||
 | 
			
		||||
	Thumbnail     []byte
 | 
			
		||||
	Type          string
 | 
			
		||||
	Content       io.Reader
 | 
			
		||||
	url           string
 | 
			
		||||
	mediaKey      []byte
 | 
			
		||||
	fileEncSha256 []byte
 | 
			
		||||
	fileSha256    []byte
 | 
			
		||||
	fileLength    uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getStickerMessage(msg *proto.WebMessageInfo) StickerMessage {
 | 
			
		||||
	sticker := msg.GetMessage().GetStickerMessage()
 | 
			
		||||
 | 
			
		||||
	StickerMessage := StickerMessage{
 | 
			
		||||
		Info:          getMessageInfo(msg),
 | 
			
		||||
		Thumbnail:     sticker.GetPngThumbnail(),
 | 
			
		||||
		url:           sticker.GetUrl(),
 | 
			
		||||
		mediaKey:      sticker.GetMediaKey(),
 | 
			
		||||
		Type:          sticker.GetMimetype(),
 | 
			
		||||
		fileEncSha256: sticker.GetFileEncSha256(),
 | 
			
		||||
		fileSha256:    sticker.GetFileSha256(),
 | 
			
		||||
		fileLength:    sticker.GetFileLength(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if contextInfo := sticker.GetContextInfo(); contextInfo != nil {
 | 
			
		||||
		StickerMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return StickerMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ParseProtoMessage(msg *proto.WebMessageInfo) interface{} {
 | 
			
		||||
	switch {
 | 
			
		||||
 | 
			
		||||
@@ -557,6 +683,9 @@ func ParseProtoMessage(msg *proto.WebMessageInfo) interface{} {
 | 
			
		||||
	case msg.GetMessage().GetLiveLocationMessage() != nil:
 | 
			
		||||
		return GetLiveLocationMessage(msg)
 | 
			
		||||
 | 
			
		||||
	case msg.GetMessage().GetStickerMessage() != nil:
 | 
			
		||||
		return getStickerMessage(msg)
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		//cannot match message
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										54
									
								
								vendor/github.com/Rhymen/go-whatsapp/session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/Rhymen/go-whatsapp/session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -7,6 +7,8 @@ import (
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@@ -88,6 +90,53 @@ func newInfoFromReq(info map[string]interface{}) *Info {
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
CheckCurrentServerVersion is based on the login method logic in order to establish the websocket connection and get
 | 
			
		||||
the current version from the server with the `admin init` command. This can be very useful for automations in which
 | 
			
		||||
you need to quickly perceive new versions (mostly patches) and update your application so it suddenly stops working.
 | 
			
		||||
*/
 | 
			
		||||
func CheckCurrentServerVersion() ([]int, error) {
 | 
			
		||||
	wac, err := NewConn(5 * time.Second)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("fail to create connection")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientId := make([]byte, 16)
 | 
			
		||||
	if _, err = rand.Read(clientId); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error creating random ClientId: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b64ClientId := base64.StdEncoding.EncodeToString(clientId)
 | 
			
		||||
	login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, b64ClientId, true}
 | 
			
		||||
	loginChan, err := wac.writeJson(login)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error writing login", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Retrieve an answer from the websocket
 | 
			
		||||
	var r string
 | 
			
		||||
	select {
 | 
			
		||||
	case r = <-loginChan:
 | 
			
		||||
	case <-time.After(wac.msgTimeout):
 | 
			
		||||
		return nil, fmt.Errorf("login connection timed out")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var resp map[string]interface{}
 | 
			
		||||
	if err = json.Unmarshal([]byte(r), &resp); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error decoding login", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Take the curr property as X.Y.Z and split it into as int slice
 | 
			
		||||
	curr := resp["curr"].(string)
 | 
			
		||||
	currArray := strings.Split(curr, ".")
 | 
			
		||||
	version := make([]int, len(currArray))
 | 
			
		||||
	for i := range version {
 | 
			
		||||
		version[i], _ = strconv.Atoi(currArray[i])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return version, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
SetClientName sets the long and short client names that are sent to WhatsApp when logging in and displayed in the
 | 
			
		||||
WhatsApp Web device list. As the values are only sent when logging in, changing them after logging in is not possible.
 | 
			
		||||
@@ -108,6 +157,11 @@ func (wac *Conn) SetClientVersion(major int, minor int, patch int) {
 | 
			
		||||
	waVersion = []int{major, minor, patch}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetClientVersion returns WhatsApp client version
 | 
			
		||||
func (wac *Conn) GetClientVersion() []int {
 | 
			
		||||
	return waVersion
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Login is the function that creates a new whatsapp session and logs you in. If you do not want to scan the qr code
 | 
			
		||||
every time, you should save the returned session and use RestoreWithSession the next time. Login takes a writable channel
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/Rhymen/go-whatsapp/write.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/Rhymen/go-whatsapp/write.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -78,13 +78,13 @@ func (wac *Conn) sendKeepAlive() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
/*
 | 
			
		||||
	When phone is unreachable, WhatsAppWeb sends ["admin","test"] time after time to try a successful contact.
 | 
			
		||||
	Tested with Airplane mode and no connection at all.
 | 
			
		||||
*/
 | 
			
		||||
func (wac *Conn) sendAdminTest() (bool, error) {
 | 
			
		||||
	data := []interface{}{"admin", "test"}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	r, err := wac.writeJson(data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, errors.Wrap(err, "error sending admin test")
 | 
			
		||||
@@ -103,9 +103,9 @@ func (wac *Conn) sendAdminTest() (bool, error) {
 | 
			
		||||
 | 
			
		||||
	if len(response) == 2 && response[0].(string) == "Pong" && response[1].(bool) == true {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	} else{
 | 
			
		||||
	} else {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}	
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (wac *Conn) write(messageType int, answerMessageTag string, data []byte) (<-chan string, error) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/bwmarrin/discordgo/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/bwmarrin/discordgo/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
# DiscordGo
 | 
			
		||||
 | 
			
		||||
[](https://godoc.org/github.com/bwmarrin/discordgo) [](http://goreportcard.com/report/bwmarrin/discordgo) [](https://travis-ci.org/bwmarrin/discordgo) [](https://discord.gg/0f1SbxBZjYoCtNPP) [](https://discord.gg/0SBTUU1wZTWT6sqd)
 | 
			
		||||
[](https://godoc.org/github.com/bwmarrin/discordgo) [](http://goreportcard.com/report/bwmarrin/discordgo) [](https://travis-ci.org/bwmarrin/discordgo) [](https://discord.gg/0f1SbxBZjYoCtNPP) [](https://discordapp.com/invite/discord-api)
 | 
			
		||||
 | 
			
		||||
<img align="right" src="http://bwmarrin.github.io/discordgo/img/discordgo.png">
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/bwmarrin/discordgo/discord.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/bwmarrin/discordgo/discord.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -21,7 +21,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
 | 
			
		||||
const VERSION = "0.19.0"
 | 
			
		||||
const VERSION = "0.20.1"
 | 
			
		||||
 | 
			
		||||
// ErrMFA will be risen by New when the user has 2FA.
 | 
			
		||||
var ErrMFA = errors.New("account has 2FA enabled")
 | 
			
		||||
@@ -58,6 +58,7 @@ func New(args ...interface{}) (s *Session, err error) {
 | 
			
		||||
		ShardCount:             1,
 | 
			
		||||
		MaxRestRetries:         3,
 | 
			
		||||
		Client:                 &http.Client{Timeout: (20 * time.Second)},
 | 
			
		||||
		UserAgent:              "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")",
 | 
			
		||||
		sequence:               new(int64),
 | 
			
		||||
		LastHeartbeatAck:       time.Now().UTC(),
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								vendor/github.com/bwmarrin/discordgo/endpoints.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/bwmarrin/discordgo/endpoints.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -38,6 +38,7 @@ var (
 | 
			
		||||
	EndpointCDNIcons        = EndpointCDN + "icons/"
 | 
			
		||||
	EndpointCDNSplashes     = EndpointCDN + "splashes/"
 | 
			
		||||
	EndpointCDNChannelIcons = EndpointCDN + "channel-icons/"
 | 
			
		||||
	EndpointCDNBanners      = EndpointCDN + "banners/"
 | 
			
		||||
 | 
			
		||||
	EndpointAuth           = EndpointAPI + "auth/"
 | 
			
		||||
	EndpointLogin          = EndpointAuth + "login"
 | 
			
		||||
@@ -92,11 +93,13 @@ var (
 | 
			
		||||
	EndpointGuildEmbed           = func(gID string) string { return EndpointGuilds + gID + "/embed" }
 | 
			
		||||
	EndpointGuildPrune           = func(gID string) string { return EndpointGuilds + gID + "/prune" }
 | 
			
		||||
	EndpointGuildIcon            = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
 | 
			
		||||
	EndpointGuildIconAnimated    = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" }
 | 
			
		||||
	EndpointGuildSplash          = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" }
 | 
			
		||||
	EndpointGuildWebhooks        = func(gID string) string { return EndpointGuilds + gID + "/webhooks" }
 | 
			
		||||
	EndpointGuildAuditLogs       = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" }
 | 
			
		||||
	EndpointGuildEmojis          = func(gID string) string { return EndpointGuilds + gID + "/emojis" }
 | 
			
		||||
	EndpointGuildEmoji           = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID }
 | 
			
		||||
	EndpointGuildBanner          = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" }
 | 
			
		||||
 | 
			
		||||
	EndpointChannel                   = func(cID string) string { return EndpointChannels + cID }
 | 
			
		||||
	EndpointChannelPermissions        = func(cID string) string { return EndpointChannels + cID + "/permissions" }
 | 
			
		||||
@@ -139,8 +142,9 @@ var (
 | 
			
		||||
	EndpointEmoji         = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".png" }
 | 
			
		||||
	EndpointEmojiAnimated = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".gif" }
 | 
			
		||||
 | 
			
		||||
	EndpointOauth2          = EndpointAPI + "oauth2/"
 | 
			
		||||
	EndpointApplications    = EndpointOauth2 + "applications"
 | 
			
		||||
	EndpointApplication     = func(aID string) string { return EndpointApplications + "/" + aID }
 | 
			
		||||
	EndpointApplicationsBot = func(aID string) string { return EndpointApplications + "/" + aID + "/bot" }
 | 
			
		||||
	EndpointOauth2            = EndpointAPI + "oauth2/"
 | 
			
		||||
	EndpointApplications      = EndpointOauth2 + "applications"
 | 
			
		||||
	EndpointApplication       = func(aID string) string { return EndpointApplications + "/" + aID }
 | 
			
		||||
	EndpointApplicationsBot   = func(aID string) string { return EndpointApplications + "/" + aID + "/bot" }
 | 
			
		||||
	EndpointApplicationAssets = func(aID string) string { return EndpointApplications + "/" + aID + "/assets" }
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/bwmarrin/discordgo/events.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/bwmarrin/discordgo/events.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -10,15 +10,15 @@ import (
 | 
			
		||||
//go:generate go run tools/cmd/eventhandlers/main.go
 | 
			
		||||
 | 
			
		||||
// Connect is the data for a Connect event.
 | 
			
		||||
// This is a sythetic event and is not dispatched by Discord.
 | 
			
		||||
// This is a synthetic event and is not dispatched by Discord.
 | 
			
		||||
type Connect struct{}
 | 
			
		||||
 | 
			
		||||
// Disconnect is the data for a Disconnect event.
 | 
			
		||||
// This is a sythetic event and is not dispatched by Discord.
 | 
			
		||||
// This is a synthetic event and is not dispatched by Discord.
 | 
			
		||||
type Disconnect struct{}
 | 
			
		||||
 | 
			
		||||
// RateLimit is the data for a RateLimit event.
 | 
			
		||||
// This is a sythetic event and is not dispatched by Discord.
 | 
			
		||||
// This is a synthetic event and is not dispatched by Discord.
 | 
			
		||||
type RateLimit struct {
 | 
			
		||||
	*TooManyRequests
 | 
			
		||||
	URL string
 | 
			
		||||
@@ -162,6 +162,8 @@ type MessageCreate struct {
 | 
			
		||||
// MessageUpdate is the data for a MessageUpdate event.
 | 
			
		||||
type MessageUpdate struct {
 | 
			
		||||
	*Message
 | 
			
		||||
	// BeforeUpdate will be nil if the Message was not previously cached in the state cache.
 | 
			
		||||
	BeforeUpdate *Message `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageDelete is the data for a MessageDelete event.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										79
									
								
								vendor/github.com/bwmarrin/discordgo/message.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/bwmarrin/discordgo/message.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -28,6 +28,11 @@ const (
 | 
			
		||||
	MessageTypeChannelIconChange
 | 
			
		||||
	MessageTypeChannelPinnedMessage
 | 
			
		||||
	MessageTypeGuildMemberJoin
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscription
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierOne
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierTwo
 | 
			
		||||
	MessageTypeUserPremiumGuildSubscriptionTierThree
 | 
			
		||||
	MessageTypeChannelFollowAdd
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Message stores all data related to a specific Discord message.
 | 
			
		||||
@@ -80,11 +85,39 @@ type Message struct {
 | 
			
		||||
	// A list of reactions to the message.
 | 
			
		||||
	Reactions []*MessageReactions `json:"reactions"`
 | 
			
		||||
 | 
			
		||||
	// Whether the message is pinned or not.
 | 
			
		||||
	Pinned bool `json:"pinned"`
 | 
			
		||||
 | 
			
		||||
	// The type of the message.
 | 
			
		||||
	Type MessageType `json:"type"`
 | 
			
		||||
 | 
			
		||||
	// The webhook ID of the message, if it was generated by a webhook
 | 
			
		||||
	WebhookID string `json:"webhook_id"`
 | 
			
		||||
 | 
			
		||||
	// Member properties for this message's author,
 | 
			
		||||
	// contains only partial information
 | 
			
		||||
	Member *Member `json:"member"`
 | 
			
		||||
 | 
			
		||||
	// Channels specifically mentioned in this message
 | 
			
		||||
	// Not all channel mentions in a message will appear in mention_channels.
 | 
			
		||||
	// Only textual channels that are visible to everyone in a lurkable guild will ever be included.
 | 
			
		||||
	// Only crossposted messages (via Channel Following) currently include mention_channels at all.
 | 
			
		||||
	// If no mentions in the message meet these requirements, this field will not be sent.
 | 
			
		||||
	MentionChannels []*Channel `json:"mention_channels"`
 | 
			
		||||
 | 
			
		||||
	// Is sent with Rich Presence-related chat embeds
 | 
			
		||||
	Activity *MessageActivity `json:"activity"`
 | 
			
		||||
 | 
			
		||||
	// Is sent with Rich Presence-related chat embeds
 | 
			
		||||
	Application *MessageApplication `json:"application"`
 | 
			
		||||
 | 
			
		||||
	// MessageReference contains reference data sent with crossposted messages
 | 
			
		||||
	MessageReference *MessageReference `json:"message_reference"`
 | 
			
		||||
 | 
			
		||||
	// The flags of the message, which describe extra features of a message.
 | 
			
		||||
	// This is a combination of bit masks; the presence of a certain permission can
 | 
			
		||||
	// be checked by performing a bitwise AND between this int and the flag.
 | 
			
		||||
	Flags int `json:"flags"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// File stores info about files you e.g. send in messages.
 | 
			
		||||
@@ -225,6 +258,52 @@ type MessageReactions struct {
 | 
			
		||||
	Emoji *Emoji `json:"emoji"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageActivity is sent with Rich Presence-related chat embeds
 | 
			
		||||
type MessageActivity struct {
 | 
			
		||||
	Type    MessageActivityType `json:"type"`
 | 
			
		||||
	PartyID string              `json:"party_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageActivityType is the type of message activity
 | 
			
		||||
type MessageActivityType int
 | 
			
		||||
 | 
			
		||||
// Constants for the different types of Message Activity
 | 
			
		||||
const (
 | 
			
		||||
	MessageActivityTypeJoin = iota + 1
 | 
			
		||||
	MessageActivityTypeSpectate
 | 
			
		||||
	MessageActivityTypeListen
 | 
			
		||||
	MessageActivityTypeJoinRequest
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MessageFlag describes an extra feature of the message
 | 
			
		||||
type MessageFlag int
 | 
			
		||||
 | 
			
		||||
// Constants for the different bit offsets of Message Flags
 | 
			
		||||
const (
 | 
			
		||||
	// This message has been published to subscribed channels (via Channel Following)
 | 
			
		||||
	MessageFlagCrossposted = 1 << iota
 | 
			
		||||
	// This message originated from a message in another channel (via Channel Following)
 | 
			
		||||
	MessageFlagIsCrosspost
 | 
			
		||||
	// Do not include any embeds when serializing this message
 | 
			
		||||
	MessageFlagSuppressEmbeds
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MessageApplication is sent with Rich Presence-related chat embeds
 | 
			
		||||
type MessageApplication struct {
 | 
			
		||||
	ID          string `json:"id"`
 | 
			
		||||
	CoverImage  string `json:"cover_image"`
 | 
			
		||||
	Description string `json:"description"`
 | 
			
		||||
	Icon        string `json:"icon"`
 | 
			
		||||
	Name        string `json:"name"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageReference contains reference data sent with crossposted messages
 | 
			
		||||
type MessageReference struct {
 | 
			
		||||
	MessageID string `json:"message_id"`
 | 
			
		||||
	ChannelID string `json:"channel_id"`
 | 
			
		||||
	GuildID   string `json:"guild_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContentWithMentionsReplaced will replace all @<id> mentions with the
 | 
			
		||||
// username of the mention.
 | 
			
		||||
func (m *Message) ContentWithMentionsReplaced() (content string) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								vendor/github.com/bwmarrin/discordgo/oauth2.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/bwmarrin/discordgo/oauth2.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -105,6 +105,25 @@ func (s *Session) ApplicationDelete(appID string) (err error) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Asset struct stores values for an asset of an application
 | 
			
		||||
type Asset struct {
 | 
			
		||||
	Type int    `json:"type"`
 | 
			
		||||
	ID   string `json:"id"`
 | 
			
		||||
	Name string `json:"name"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ApplicationAssets returns an application's assets
 | 
			
		||||
func (s *Session) ApplicationAssets(appID string) (ass []*Asset, err error) {
 | 
			
		||||
 | 
			
		||||
	body, err := s.RequestWithBucketID("GET", EndpointApplicationAssets(appID), nil, EndpointApplicationAssets(""))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = unmarshal(body, &ass)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------------------------------------
 | 
			
		||||
// Code specific to Discord OAuth2 Application Bots
 | 
			
		||||
// ------------------------------------------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/github.com/bwmarrin/discordgo/restapi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/bwmarrin/discordgo/restapi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -90,7 +90,7 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
 | 
			
		||||
 | 
			
		||||
	req.Header.Set("Content-Type", contentType)
 | 
			
		||||
	// TODO: Make a configurable static variable.
 | 
			
		||||
	req.Header.Set("User-Agent", "DiscordBot (https://github.com/bwmarrin/discordgo, v"+VERSION+")")
 | 
			
		||||
	req.Header.Set("User-Agent", s.UserAgent)
 | 
			
		||||
 | 
			
		||||
	if s.Debug {
 | 
			
		||||
		for k, v := range req.Header {
 | 
			
		||||
@@ -617,10 +617,10 @@ func (s *Session) GuildCreate(name string) (st *Guild, err error) {
 | 
			
		||||
// g 		 : A GuildParams struct with the values Name, Region and VerificationLevel defined.
 | 
			
		||||
func (s *Session) GuildEdit(guildID string, g GuildParams) (st *Guild, err error) {
 | 
			
		||||
 | 
			
		||||
	// Bounds checking for VerificationLevel, interval: [0, 3]
 | 
			
		||||
	// Bounds checking for VerificationLevel, interval: [0, 4]
 | 
			
		||||
	if g.VerificationLevel != nil {
 | 
			
		||||
		val := *g.VerificationLevel
 | 
			
		||||
		if val < 0 || val > 3 {
 | 
			
		||||
		if val < 0 || val > 4 {
 | 
			
		||||
			err = ErrVerificationLevelBounds
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
@@ -2067,7 +2067,7 @@ func (s *Session) WebhookDeleteWithToken(webhookID, token string) (st *Webhook,
 | 
			
		||||
// WebhookExecute executes a webhook.
 | 
			
		||||
// webhookID: The ID of a webhook.
 | 
			
		||||
// token    : The auth token for the webhook
 | 
			
		||||
// wait     : Wait for server to confirm the message arrival
 | 
			
		||||
// wait     : Waits for server confirmation of message send and ensures that the return struct is populated (it is nil otherwise)
 | 
			
		||||
//
 | 
			
		||||
// If `wait` is `false`, the returned *Message is always empty, because server
 | 
			
		||||
// does not provide the response data.
 | 
			
		||||
@@ -2150,6 +2150,8 @@ func (s *Session) WebhookExecute(webhookID, token string, wait bool, data *Webho
 | 
			
		||||
// emojiID   : Either the unicode emoji for the reaction, or a guild emoji identifier.
 | 
			
		||||
func (s *Session) MessageReactionAdd(channelID, messageID, emojiID string) error {
 | 
			
		||||
 | 
			
		||||
	// emoji such as  #⃣ need to have # escaped
 | 
			
		||||
	emojiID = strings.Replace(emojiID, "#", "%23", -1)
 | 
			
		||||
	_, err := s.RequestWithBucketID("PUT", EndpointMessageReaction(channelID, messageID, emojiID, "@me"), nil, EndpointMessageReaction(channelID, "", "", ""))
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
@@ -2162,6 +2164,8 @@ func (s *Session) MessageReactionAdd(channelID, messageID, emojiID string) error
 | 
			
		||||
// userID	 : @me or ID of the user to delete the reaction for.
 | 
			
		||||
func (s *Session) MessageReactionRemove(channelID, messageID, emojiID, userID string) error {
 | 
			
		||||
 | 
			
		||||
	// emoji such as  #⃣ need to have # escaped
 | 
			
		||||
	emojiID = strings.Replace(emojiID, "#", "%23", -1)
 | 
			
		||||
	_, err := s.RequestWithBucketID("DELETE", EndpointMessageReaction(channelID, messageID, emojiID, userID), nil, EndpointMessageReaction(channelID, "", "", ""))
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
@@ -2183,6 +2187,8 @@ func (s *Session) MessageReactionsRemoveAll(channelID, messageID string) error {
 | 
			
		||||
// emojiID   : Either the unicode emoji for the reaction, or a guild emoji identifier.
 | 
			
		||||
// limit    : max number of users to return (max 100)
 | 
			
		||||
func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit int) (st []*User, err error) {
 | 
			
		||||
	// emoji such as  #⃣ need to have # escaped
 | 
			
		||||
	emojiID = strings.Replace(emojiID, "#", "%23", -1)
 | 
			
		||||
	uri := EndpointMessageReactions(channelID, messageID, emojiID)
 | 
			
		||||
 | 
			
		||||
	v := url.Values{}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/bwmarrin/discordgo/state.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/bwmarrin/discordgo/state.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -882,6 +882,13 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
 | 
			
		||||
		}
 | 
			
		||||
	case *MessageUpdate:
 | 
			
		||||
		if s.MaxMessageCount != 0 {
 | 
			
		||||
			var old *Message
 | 
			
		||||
			old, err = s.Message(t.ChannelID, t.ID)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				oldCopy := *old
 | 
			
		||||
				t.BeforeUpdate = &oldCopy
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = s.MessageAdd(t.Message)
 | 
			
		||||
		}
 | 
			
		||||
	case *MessageDelete:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										66
									
								
								vendor/github.com/bwmarrin/discordgo/structs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										66
									
								
								vendor/github.com/bwmarrin/discordgo/structs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -15,6 +15,7 @@ import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@@ -82,6 +83,9 @@ type Session struct {
 | 
			
		||||
	// The http client used for REST requests
 | 
			
		||||
	Client *http.Client
 | 
			
		||||
 | 
			
		||||
	// The user agent used for REST APIs
 | 
			
		||||
	UserAgent string
 | 
			
		||||
 | 
			
		||||
	// Stores the last HeartbeatAck that was recieved (in UTC)
 | 
			
		||||
	LastHeartbeatAck time.Time
 | 
			
		||||
 | 
			
		||||
@@ -196,6 +200,8 @@ const (
 | 
			
		||||
	ChannelTypeGuildVoice
 | 
			
		||||
	ChannelTypeGroupDM
 | 
			
		||||
	ChannelTypeGuildCategory
 | 
			
		||||
	ChannelTypeGuildNews
 | 
			
		||||
	ChannelTypeGuildStore
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Channel holds all data related to an individual Discord channel.
 | 
			
		||||
@@ -220,6 +226,10 @@ type Channel struct {
 | 
			
		||||
	// guaranteed to be an ID of a valid message.
 | 
			
		||||
	LastMessageID string `json:"last_message_id"`
 | 
			
		||||
 | 
			
		||||
	// The timestamp of the last pinned message in the channel.
 | 
			
		||||
	// Empty if the channel has no pinned messages.
 | 
			
		||||
	LastPinTimestamp Timestamp `json:"last_pin_timestamp"`
 | 
			
		||||
 | 
			
		||||
	// Whether the channel is marked as NSFW.
 | 
			
		||||
	NSFW bool `json:"nsfw"`
 | 
			
		||||
 | 
			
		||||
@@ -247,6 +257,10 @@ type Channel struct {
 | 
			
		||||
 | 
			
		||||
	// The ID of the parent channel, if the channel is under a category
 | 
			
		||||
	ParentID string `json:"parent_id"`
 | 
			
		||||
 | 
			
		||||
	// Amount of seconds a user has to wait before sending another message (0-21600)
 | 
			
		||||
	// bots, as well as users with the permission manage_messages or manage_channel, are unaffected
 | 
			
		||||
	RateLimitPerUser int `json:"rate_limit_per_user"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mention returns a string which mentions the channel
 | 
			
		||||
@@ -283,6 +297,7 @@ type Emoji struct {
 | 
			
		||||
	Managed       bool     `json:"managed"`
 | 
			
		||||
	RequireColons bool     `json:"require_colons"`
 | 
			
		||||
	Animated      bool     `json:"animated"`
 | 
			
		||||
	Available     bool     `json:"available"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageFormat returns a correctly formatted Emoji for use in Message content and embeds
 | 
			
		||||
@@ -312,12 +327,13 @@ func (e *Emoji) APIName() string {
 | 
			
		||||
// VerificationLevel type definition
 | 
			
		||||
type VerificationLevel int
 | 
			
		||||
 | 
			
		||||
// Constants for VerificationLevel levels from 0 to 3 inclusive
 | 
			
		||||
// Constants for VerificationLevel levels from 0 to 4 inclusive
 | 
			
		||||
const (
 | 
			
		||||
	VerificationLevelNone VerificationLevel = iota
 | 
			
		||||
	VerificationLevelLow
 | 
			
		||||
	VerificationLevelMedium
 | 
			
		||||
	VerificationLevelHigh
 | 
			
		||||
	VerificationLevelVeryHigh
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ExplicitContentFilterLevel type definition
 | 
			
		||||
@@ -339,6 +355,17 @@ const (
 | 
			
		||||
	MfaLevelElevated
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PremiumTier type definition
 | 
			
		||||
type PremiumTier int
 | 
			
		||||
 | 
			
		||||
// Constants for PremiumTier levels from 0 to 3 inclusive
 | 
			
		||||
const (
 | 
			
		||||
	PremiumTierNone PremiumTier = iota
 | 
			
		||||
	PremiumTier1
 | 
			
		||||
	PremiumTier2
 | 
			
		||||
	PremiumTier3
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Guild holds all data related to a specific Discord Guild.  Guilds are also
 | 
			
		||||
// sometimes referred to as Servers in the Discord client.
 | 
			
		||||
type Guild struct {
 | 
			
		||||
@@ -443,6 +470,34 @@ type Guild struct {
 | 
			
		||||
 | 
			
		||||
	// The Channel ID to which system messages are sent (eg join and leave messages)
 | 
			
		||||
	SystemChannelID string `json:"system_channel_id"`
 | 
			
		||||
 | 
			
		||||
	// the vanity url code for the guild
 | 
			
		||||
	VanityURLCode string `json:"vanity_url_code"`
 | 
			
		||||
 | 
			
		||||
	// the description for the guild
 | 
			
		||||
	Description string `json:"description"`
 | 
			
		||||
 | 
			
		||||
	// The hash of the guild's banner
 | 
			
		||||
	Banner string `json:"banner"`
 | 
			
		||||
 | 
			
		||||
	// The premium tier of the guild
 | 
			
		||||
	PremiumTier PremiumTier `json:"premium_tier"`
 | 
			
		||||
 | 
			
		||||
	// The total number of users currently boosting this server
 | 
			
		||||
	PremiumSubscriptionCount int `json:"premium_subscription_count"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IconURL returns a URL to the guild's icon.
 | 
			
		||||
func (g *Guild) IconURL() string {
 | 
			
		||||
	if g.Icon == "" {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if strings.HasPrefix(g.Icon, "a_") {
 | 
			
		||||
		return EndpointGuildIconAnimated(g.ID, g.Icon)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return EndpointGuildIcon(g.ID, g.Icon)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A UserGuild holds a brief version of a Guild
 | 
			
		||||
@@ -617,6 +672,9 @@ type Member struct {
 | 
			
		||||
 | 
			
		||||
	// A list of IDs of the roles which are possessed by the member.
 | 
			
		||||
	Roles []string `json:"roles"`
 | 
			
		||||
 | 
			
		||||
	// When the user used their Nitro boost on the server
 | 
			
		||||
	PremiumSince Timestamp `json:"premium_since"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mention creates a member mention
 | 
			
		||||
@@ -872,6 +930,7 @@ const (
 | 
			
		||||
	PermissionVoiceDeafenMembers
 | 
			
		||||
	PermissionVoiceMoveMembers
 | 
			
		||||
	PermissionVoiceUseVAD
 | 
			
		||||
	PermissionVoicePrioritySpeaker = 1 << (iota + 2)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Constants for general management.
 | 
			
		||||
@@ -907,7 +966,8 @@ const (
 | 
			
		||||
		PermissionVoiceMuteMembers |
 | 
			
		||||
		PermissionVoiceDeafenMembers |
 | 
			
		||||
		PermissionVoiceMoveMembers |
 | 
			
		||||
		PermissionVoiceUseVAD
 | 
			
		||||
		PermissionVoiceUseVAD |
 | 
			
		||||
		PermissionVoicePrioritySpeaker
 | 
			
		||||
	PermissionAllChannel = PermissionAllText |
 | 
			
		||||
		PermissionAllVoice |
 | 
			
		||||
		PermissionCreateInstantInvite |
 | 
			
		||||
@@ -956,7 +1016,7 @@ const (
 | 
			
		||||
	ErrCodeMissingAccess                             = 50001
 | 
			
		||||
	ErrCodeInvalidAccountType                        = 50002
 | 
			
		||||
	ErrCodeCannotExecuteActionOnDMChannel            = 50003
 | 
			
		||||
	ErrCodeEmbedCisabled                             = 50004
 | 
			
		||||
	ErrCodeEmbedDisabled                             = 50004
 | 
			
		||||
	ErrCodeCannotEditFromAnotherUser                 = 50005
 | 
			
		||||
	ErrCodeCannotSendEmptyMessage                    = 50006
 | 
			
		||||
	ErrCodeCannotSendMessagesToThisUser              = 50007
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/github.com/bwmarrin/discordgo/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/bwmarrin/discordgo/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
package discordgo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SnowflakeTimestamp returns the creation time of a Snowflake ID relative to the creation of Discord.
 | 
			
		||||
func SnowflakeTimestamp(ID string) (t time.Time, err error) {
 | 
			
		||||
	i, err := strconv.ParseInt(ID, 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	timestamp := (i >> 22) + 1420070400000
 | 
			
		||||
	t = time.Unix(timestamp/1000, 0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/bwmarrin/discordgo/voice.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/bwmarrin/discordgo/voice.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -243,6 +243,7 @@ type voiceOP2 struct {
 | 
			
		||||
	Port              int           `json:"port"`
 | 
			
		||||
	Modes             []string      `json:"modes"`
 | 
			
		||||
	HeartbeatInterval time.Duration `json:"heartbeat_interval"`
 | 
			
		||||
	IP                string        `json:"ip"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WaitUntilConnected waits for the Voice Connection to
 | 
			
		||||
@@ -542,7 +543,7 @@ func (v *VoiceConnection) udpOpen() (err error) {
 | 
			
		||||
		return fmt.Errorf("empty endpoint")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	host := strings.TrimSuffix(v.endpoint, ":80") + ":" + strconv.Itoa(v.op2.Port)
 | 
			
		||||
	host := v.op2.IP + ":" + strconv.Itoa(v.op2.Port)
 | 
			
		||||
	addr, err := net.ResolveUDPAddr("udp", host)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		v.log(LogWarning, "error resolving udp host %s, %s", host, err)
 | 
			
		||||
@@ -593,7 +594,7 @@ func (v *VoiceConnection) udpOpen() (err error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Grab port from position 68 and 69
 | 
			
		||||
	port := binary.LittleEndian.Uint16(rb[68:70])
 | 
			
		||||
	port := binary.BigEndian.Uint16(rb[68:70])
 | 
			
		||||
 | 
			
		||||
	// Take the data from above and send it back to Discord to finalize
 | 
			
		||||
	// the UDP connection handshake.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/bwmarrin/discordgo/wsapi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/bwmarrin/discordgo/wsapi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -261,7 +261,6 @@ type heartbeatOp struct {
 | 
			
		||||
 | 
			
		||||
type helloOp struct {
 | 
			
		||||
	HeartbeatInterval time.Duration `json:"heartbeat_interval"`
 | 
			
		||||
	Trace             []string      `json:"_trace"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FailedHeartbeatAcks is the Number of heartbeat intervals to wait until forcing a connection restart.
 | 
			
		||||
@@ -615,11 +614,7 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi
 | 
			
		||||
	voice.session = s
 | 
			
		||||
	voice.Unlock()
 | 
			
		||||
 | 
			
		||||
	// Send the request to Discord that we want to join the voice channel
 | 
			
		||||
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
 | 
			
		||||
	s.wsMutex.Lock()
 | 
			
		||||
	err = s.wsConn.WriteJSON(data)
 | 
			
		||||
	s.wsMutex.Unlock()
 | 
			
		||||
	err = s.ChannelVoiceJoinManual(gID, cID, mute, deaf)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -640,22 +635,25 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi
 | 
			
		||||
// This should only be used when the VoiceServerUpdate will be intercepted and used elsewhere.
 | 
			
		||||
//
 | 
			
		||||
//    gID     : Guild ID of the channel to join.
 | 
			
		||||
//    cID     : Channel ID of the channel to join.
 | 
			
		||||
//    cID     : Channel ID of the channel to join, leave empty to disconnect.
 | 
			
		||||
//    mute    : If true, you will be set to muted upon joining.
 | 
			
		||||
//    deaf    : If true, you will be set to deafened upon joining.
 | 
			
		||||
func (s *Session) ChannelVoiceJoinManual(gID, cID string, mute, deaf bool) (err error) {
 | 
			
		||||
 | 
			
		||||
	s.log(LogInformational, "called")
 | 
			
		||||
 | 
			
		||||
	var channelID *string
 | 
			
		||||
	if cID == "" {
 | 
			
		||||
		channelID = nil
 | 
			
		||||
	} else {
 | 
			
		||||
		channelID = &cID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send the request to Discord that we want to join the voice channel
 | 
			
		||||
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
 | 
			
		||||
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, channelID, mute, deaf}}
 | 
			
		||||
	s.wsMutex.Lock()
 | 
			
		||||
	err = s.wsConn.WriteJSON(data)
 | 
			
		||||
	s.wsMutex.Unlock()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/d5/tengo/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/d5/tengo/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,8 @@
 | 
			
		||||
env:
 | 
			
		||||
  - GO111MODULE=on
 | 
			
		||||
before:
 | 
			
		||||
  hooks:
 | 
			
		||||
    - go mod tidy
 | 
			
		||||
builds:
 | 
			
		||||
  - env:
 | 
			
		||||
      - CGO_ENABLED=0
 | 
			
		||||
@@ -9,6 +14,7 @@ builds:
 | 
			
		||||
  - env:
 | 
			
		||||
      - CGO_ENABLED=0
 | 
			
		||||
    main: ./cmd/tengomin/main.go
 | 
			
		||||
    id: tengomin
 | 
			
		||||
    binary: tengomin
 | 
			
		||||
    goos:
 | 
			
		||||
      - darwin
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										0
									
								
								vendor/github.com/d5/tengo/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								vendor/github.com/d5/tengo/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										20
									
								
								vendor/github.com/d5/tengo/stdlib/base64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/d5/tengo/stdlib/base64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
package stdlib
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"github.com/d5/tengo/objects"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var base64Module = map[string]objects.Object{
 | 
			
		||||
	"encode": &objects.UserFunction{Value: FuncAYRS(base64.StdEncoding.EncodeToString)},
 | 
			
		||||
	"decode": &objects.UserFunction{Value: FuncASRYE(base64.StdEncoding.DecodeString)},
 | 
			
		||||
 | 
			
		||||
	"raw_encode": &objects.UserFunction{Value: FuncAYRS(base64.RawStdEncoding.EncodeToString)},
 | 
			
		||||
	"raw_decode": &objects.UserFunction{Value: FuncASRYE(base64.RawStdEncoding.DecodeString)},
 | 
			
		||||
 | 
			
		||||
	"url_encode": &objects.UserFunction{Value: FuncAYRS(base64.URLEncoding.EncodeToString)},
 | 
			
		||||
	"url_decode": &objects.UserFunction{Value: FuncASRYE(base64.URLEncoding.DecodeString)},
 | 
			
		||||
 | 
			
		||||
	"raw_url_encode": &objects.UserFunction{Value: FuncAYRS(base64.RawURLEncoding.EncodeToString)},
 | 
			
		||||
	"raw_url_decode": &objects.UserFunction{Value: FuncASRYE(base64.RawURLEncoding.DecodeString)},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/d5/tengo/stdlib/builtin_modules.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/d5/tengo/stdlib/builtin_modules.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -11,4 +11,6 @@ var BuiltinModules = map[string]map[string]objects.Object{
 | 
			
		||||
	"rand":  randModule,
 | 
			
		||||
	"fmt":   fmtModule,
 | 
			
		||||
	"json":  jsonModule,
 | 
			
		||||
	"base64": base64Module,
 | 
			
		||||
	"hex":  hexModule,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								vendor/github.com/d5/tengo/stdlib/func_typedefs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								vendor/github.com/d5/tengo/stdlib/func_typedefs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1036,6 +1036,29 @@ func FuncAYRIE(fn func([]byte) (int, error)) objects.CallableFunc {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FuncAYRS transform a function of 'func([]byte) string' signature
 | 
			
		||||
// into CallableFunc type.
 | 
			
		||||
func FuncAYRS(fn func([]byte) string) objects.CallableFunc {
 | 
			
		||||
	return func(args ...objects.Object) (ret objects.Object, err error) {
 | 
			
		||||
		if len(args) != 1 {
 | 
			
		||||
			return nil, objects.ErrWrongNumArguments
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		y1, ok := objects.ToByteSlice(args[0])
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, objects.ErrInvalidArgumentType{
 | 
			
		||||
				Name:     "first",
 | 
			
		||||
				Expected: "bytes(compatible)",
 | 
			
		||||
				Found:    args[0].TypeName(),
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		res := fn(y1)
 | 
			
		||||
 | 
			
		||||
		return &objects.String{Value: res}, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FuncASRIE transform a function of 'func(string) (int, error)' signature
 | 
			
		||||
// into CallableFunc type.
 | 
			
		||||
func FuncASRIE(fn func(string) (int, error)) objects.CallableFunc {
 | 
			
		||||
@@ -1062,6 +1085,36 @@ func FuncASRIE(fn func(string) (int, error)) objects.CallableFunc {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FuncASRYE transform a function of 'func(string) ([]byte, error)' signature
 | 
			
		||||
// into CallableFunc type.
 | 
			
		||||
func FuncASRYE(fn func(string) ([]byte, error)) objects.CallableFunc {
 | 
			
		||||
	return func(args ...objects.Object) (ret objects.Object, err error) {
 | 
			
		||||
		if len(args) != 1 {
 | 
			
		||||
			return nil, objects.ErrWrongNumArguments
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		s1, ok := objects.ToString(args[0])
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, objects.ErrInvalidArgumentType{
 | 
			
		||||
				Name:     "first",
 | 
			
		||||
				Expected: "string(compatible)",
 | 
			
		||||
				Found:    args[0].TypeName(),
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		res, err := fn(s1)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return wrapError(err), nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(res) > tengo.MaxBytesLen {
 | 
			
		||||
			return nil, objects.ErrBytesLimit
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return &objects.Bytes{Value: res}, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FuncAIRSsE transform a function of 'func(int) ([]string, error)' signature
 | 
			
		||||
// into CallableFunc type.
 | 
			
		||||
func FuncAIRSsE(fn func(int) ([]string, error)) objects.CallableFunc {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/github.com/d5/tengo/stdlib/hex.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/d5/tengo/stdlib/hex.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
package stdlib
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"github.com/d5/tengo/objects"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var hexModule = map[string]objects.Object{
 | 
			
		||||
	"encode": &objects.UserFunction{Value: FuncAYRS(hex.EncodeToString)},
 | 
			
		||||
	"decode": &objects.UserFunction{Value: FuncASRYE(hex.DecodeString)},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/gomarkdown/markdown/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/gomarkdown/markdown/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
*.out
 | 
			
		||||
*.swp
 | 
			
		||||
*.8
 | 
			
		||||
*.6
 | 
			
		||||
_obj
 | 
			
		||||
_test*
 | 
			
		||||
markdown
 | 
			
		||||
tags
 | 
			
		||||
fuzz-workdir/
 | 
			
		||||
markdown-fuzz.zip
 | 
			
		||||
coverage.txt
 | 
			
		||||
testdata/*_got.md
 | 
			
		||||
testdata/*_ast.txt
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/gomarkdown/markdown/.gitpod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/gomarkdown/markdown/.gitpod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
checkoutLocation: "src/github.com/gomarkdown/markdown"
 | 
			
		||||
workspaceLocation: "."
 | 
			
		||||
tasks:
 | 
			
		||||
  - command: >
 | 
			
		||||
      cd /workspace/src/github.com/gomarkdown/markdown &&
 | 
			
		||||
      go get -v ./... &&
 | 
			
		||||
      go test -c
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/github.com/gomarkdown/markdown/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/gomarkdown/markdown/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
dist: bionic
 | 
			
		||||
language: go
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - "1.12.x"
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - go build -v ./...
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - go test -v ./...
 | 
			
		||||
  - go test -run=^$ -bench=BenchmarkReference -benchmem
 | 
			
		||||
  - ./s/test_with_codecoverage.sh
 | 
			
		||||
  - ./s/ci_fuzzit.sh
 | 
			
		||||
 | 
			
		||||
after_success:
 | 
			
		||||
  - bash <(curl -s https://codecov.io/bash)
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/github.com/gomarkdown/markdown/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/gomarkdown/markdown/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
Markdown is distributed under the Simplified BSD License:
 | 
			
		||||
 | 
			
		||||
Copyright © 2011 Russ Ross
 | 
			
		||||
Copyright © 2018 Krzysztof Kowalczyk
 | 
			
		||||
Copyright © 2018 Authors
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions
 | 
			
		||||
are met:
 | 
			
		||||
 | 
			
		||||
1.  Redistributions of source code must retain the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
2.  Redistributions in binary form must reproduce the above
 | 
			
		||||
    copyright notice, this list of conditions and the following
 | 
			
		||||
    disclaimer in the documentation and/or other materials provided with
 | 
			
		||||
    the distribution.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
			
		||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
			
		||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 | 
			
		||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										325
									
								
								vendor/github.com/gomarkdown/markdown/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								vendor/github.com/gomarkdown/markdown/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,325 @@
 | 
			
		||||
# Markdown Parser and HTML Renderer for Go
 | 
			
		||||
 | 
			
		||||
[](https://godoc.org/github.com/gomarkdown/markdown) [](https://codecov.io/gh/gomarkdown/markdown)
 | 
			
		||||
 | 
			
		||||
Package `github.com/gomarkdown/markdown` is a very fast Go library for parsing [Markdown](https://daringfireball.net/projects/markdown/) documents and rendering them to HTML.
 | 
			
		||||
 | 
			
		||||
It's fast and supports common extensions.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
    go get -u github.com/gomarkdown/markdown
 | 
			
		||||
 | 
			
		||||
API Docs:
 | 
			
		||||
 | 
			
		||||
- https://godoc.org/github.com/gomarkdown/markdown : top level package
 | 
			
		||||
- https://godoc.org/github.com/gomarkdown/markdown/ast : defines abstract syntax tree of parsed markdown document
 | 
			
		||||
- https://godoc.org/github.com/gomarkdown/markdown/parser : parser
 | 
			
		||||
- https://godoc.org/github.com/gomarkdown/markdown/html : html renderer
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
To convert markdown text to HTML using reasonable defaults:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
md := []byte("## markdown document")
 | 
			
		||||
output := markdown.ToHTML(md, nil, nil)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Customizing markdown parser
 | 
			
		||||
 | 
			
		||||
Markdown format is loosely specified and there are multiple extensions invented after original specification was created.
 | 
			
		||||
 | 
			
		||||
The parser supports several [extensions](https://godoc.org/github.com/gomarkdown/markdown/parser#Extensions).
 | 
			
		||||
 | 
			
		||||
Default parser uses most common `parser.CommonExtensions` but you can easily use parser with custom extension:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
import (
 | 
			
		||||
    "github.com/gomarkdown/markdown"
 | 
			
		||||
    "github.com/gomarkdown/markdown/parser"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
extensions := parser.CommonExtensions | parser.AutoHeadingIDs
 | 
			
		||||
parser := parser.NewWithExtensions(extensions)
 | 
			
		||||
 | 
			
		||||
md := []byte("markdown text")
 | 
			
		||||
html := markdown.ToHTML(md, parser, nil)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Customizing HTML renderer
 | 
			
		||||
 | 
			
		||||
Similarly, HTML renderer can be configured with different [options](https://godoc.org/github.com/gomarkdown/markdown/html#RendererOptions)
 | 
			
		||||
 | 
			
		||||
Here's how to use a custom renderer:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
import (
 | 
			
		||||
    "github.com/gomarkdown/markdown"
 | 
			
		||||
    "github.com/gomarkdown/markdown/html"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
htmlFlags := html.CommonFlags | html.HrefTargetBlank
 | 
			
		||||
opts := html.RendererOptions{Flags: htmlFlags}
 | 
			
		||||
renderer := html.NewRenderer(opts)
 | 
			
		||||
 | 
			
		||||
md := []byte("markdown text")
 | 
			
		||||
html := markdown.ToHTML(md, nil, renderer)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
HTML renderer also supports reusing most of the logic and overriding rendering of only specifc nodes.
 | 
			
		||||
 | 
			
		||||
You can provide [RenderNodeFunc](https://godoc.org/github.com/gomarkdown/markdown/html#RenderNodeFunc) in [RendererOptions](https://godoc.org/github.com/gomarkdown/markdown/html#RendererOptions).
 | 
			
		||||
 | 
			
		||||
The function is called for each node in AST, you can implement custom rendering logic and tell HTML renderer to skip rendering this node.
 | 
			
		||||
 | 
			
		||||
Here's the simplest example that drops all code blocks from the output:
 | 
			
		||||
 | 
			
		||||
````go
 | 
			
		||||
import (
 | 
			
		||||
    "github.com/gomarkdown/markdown"
 | 
			
		||||
    "github.com/gomarkdown/markdown/ast"
 | 
			
		||||
    "github.com/gomarkdown/markdown/html"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// return (ast.GoToNext, true) to tell html renderer to skip rendering this node
 | 
			
		||||
// (because you've rendered it)
 | 
			
		||||
func renderHookDropCodeBlock(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
 | 
			
		||||
    // skip all nodes that are not CodeBlock nodes
 | 
			
		||||
	if _, ok := node.(*ast.CodeBlock); !ok {
 | 
			
		||||
		return ast.GoToNext, false
 | 
			
		||||
    }
 | 
			
		||||
    // custom rendering logic for ast.CodeBlock. By doing nothing it won't be
 | 
			
		||||
    // present in the output
 | 
			
		||||
	return ast.GoToNext, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
opts := html.RendererOptions{
 | 
			
		||||
    Flags: html.CommonFlags,
 | 
			
		||||
    RenderNodeHook: renderHookDropCodeBlock,
 | 
			
		||||
}
 | 
			
		||||
renderer := html.NewRenderer(opts)
 | 
			
		||||
md := "test\n```\nthis code block will be dropped from output\n```\ntext"
 | 
			
		||||
html := markdown.ToHTML([]byte(s), nil, renderer)
 | 
			
		||||
````
 | 
			
		||||
 | 
			
		||||
## Sanitize untrusted content
 | 
			
		||||
 | 
			
		||||
We don't protect against malicious content. When dealing with user-provided
 | 
			
		||||
markdown, run renderer HTML through HTML sanitizer such as [Bluemonday](https://github.com/microcosm-cc/bluemonday).
 | 
			
		||||
 | 
			
		||||
Here's an example of simple usage with Bluemonday:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
import (
 | 
			
		||||
    "github.com/microcosm-cc/bluemonday"
 | 
			
		||||
    "github.com/gomarkdown/markdown"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ...
 | 
			
		||||
maybeUnsafeHTML := markdown.ToHTML(md, nil, nil)
 | 
			
		||||
html := bluemonday.UGCPolicy().SanitizeBytes(maybeUnsafeHTML)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## mdtohtml command-line tool
 | 
			
		||||
 | 
			
		||||
https://github.com/gomarkdown/mdtohtml is a command-line markdown to html
 | 
			
		||||
converter built using this library.
 | 
			
		||||
 | 
			
		||||
You can also use it as an example of how to use the library.
 | 
			
		||||
 | 
			
		||||
You can install it with:
 | 
			
		||||
 | 
			
		||||
    go get -u github.com/gomarkdown/mdtohtml
 | 
			
		||||
 | 
			
		||||
To run: `mdtohtml input-file [output-file]`
 | 
			
		||||
 | 
			
		||||
## Features
 | 
			
		||||
 | 
			
		||||
- **Compatibility**. The Markdown v1.0.3 test suite passes with
 | 
			
		||||
  the `--tidy` option. Without `--tidy`, the differences are
 | 
			
		||||
  mostly in whitespace and entity escaping, where this package is
 | 
			
		||||
  more consistent and cleaner.
 | 
			
		||||
 | 
			
		||||
- **Common extensions**, including table support, fenced code
 | 
			
		||||
  blocks, autolinks, strikethroughs, non-strict emphasis, etc.
 | 
			
		||||
 | 
			
		||||
- **Safety**. Markdown is paranoid when parsing, making it safe
 | 
			
		||||
  to feed untrusted user input without fear of bad things
 | 
			
		||||
  happening. The test suite stress tests this and there are no
 | 
			
		||||
  known inputs that make it crash. If you find one, please let me
 | 
			
		||||
  know and send me the input that does it.
 | 
			
		||||
 | 
			
		||||
  NOTE: "safety" in this context means _runtime safety only_. In order to
 | 
			
		||||
  protect yourself against JavaScript injection in untrusted content, see
 | 
			
		||||
  [this example](https://github.com/gomarkdown/markdown#sanitize-untrusted-content).
 | 
			
		||||
 | 
			
		||||
- **Fast**. It is fast enough to render on-demand in
 | 
			
		||||
  most web applications without having to cache the output.
 | 
			
		||||
 | 
			
		||||
- **Thread safety**. You can run multiple parsers in different
 | 
			
		||||
  goroutines without ill effect. There is no dependence on global
 | 
			
		||||
  shared state.
 | 
			
		||||
 | 
			
		||||
- **Minimal dependencies**. Only depends on standard library packages in Go.
 | 
			
		||||
 | 
			
		||||
- **Standards compliant**. Output successfully validates using the
 | 
			
		||||
  W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
 | 
			
		||||
 | 
			
		||||
## Extensions
 | 
			
		||||
 | 
			
		||||
In addition to the standard markdown syntax, this package
 | 
			
		||||
implements the following extensions:
 | 
			
		||||
 | 
			
		||||
- **Intra-word emphasis supression**. The `_` character is
 | 
			
		||||
  commonly used inside words when discussing code, so having
 | 
			
		||||
  markdown interpret it as an emphasis command is usually the
 | 
			
		||||
  wrong thing. We let you treat all emphasis markers as
 | 
			
		||||
  normal characters when they occur inside a word.
 | 
			
		||||
 | 
			
		||||
- **Tables**. Tables can be created by drawing them in the input
 | 
			
		||||
  using a simple syntax:
 | 
			
		||||
 | 
			
		||||
  ```
 | 
			
		||||
  Name    | Age
 | 
			
		||||
  --------|------
 | 
			
		||||
  Bob     | 27
 | 
			
		||||
  Alice   | 23
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
  Table footers are supported as well and can be added with equal signs (`=`):
 | 
			
		||||
 | 
			
		||||
  ```
 | 
			
		||||
  Name    | Age
 | 
			
		||||
  --------|------
 | 
			
		||||
  Bob     | 27
 | 
			
		||||
  Alice   | 23
 | 
			
		||||
  ========|======
 | 
			
		||||
  Total   | 50
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
- **Fenced code blocks**. In addition to the normal 4-space
 | 
			
		||||
  indentation to mark code blocks, you can explicitly mark them
 | 
			
		||||
  and supply a language (to make syntax highlighting simple). Just
 | 
			
		||||
  mark it like this:
 | 
			
		||||
 | 
			
		||||
      ```go
 | 
			
		||||
      func getTrue() bool {
 | 
			
		||||
          return true
 | 
			
		||||
      }
 | 
			
		||||
      ```
 | 
			
		||||
 | 
			
		||||
  You can use 3 or more backticks to mark the beginning of the
 | 
			
		||||
  block, and the same number to mark the end of the block.
 | 
			
		||||
 | 
			
		||||
- **Definition lists**. A simple definition list is made of a single-line
 | 
			
		||||
  term followed by a colon and the definition for that term.
 | 
			
		||||
 | 
			
		||||
      Cat
 | 
			
		||||
      : Fluffy animal everyone likes
 | 
			
		||||
 | 
			
		||||
      Internet
 | 
			
		||||
      : Vector of transmission for pictures of cats
 | 
			
		||||
 | 
			
		||||
  Terms must be separated from the previous definition by a blank line.
 | 
			
		||||
 | 
			
		||||
- **Footnotes**. A marker in the text that will become a superscript number;
 | 
			
		||||
  a footnote definition that will be placed in a list of footnotes at the
 | 
			
		||||
  end of the document. A footnote looks like this:
 | 
			
		||||
 | 
			
		||||
      This is a footnote.[^1]
 | 
			
		||||
 | 
			
		||||
      [^1]: the footnote text.
 | 
			
		||||
 | 
			
		||||
- **Autolinking**. We can find URLs that have not been
 | 
			
		||||
  explicitly marked as links and turn them into links.
 | 
			
		||||
 | 
			
		||||
- **Strikethrough**. Use two tildes (`~~`) to mark text that
 | 
			
		||||
  should be crossed out.
 | 
			
		||||
 | 
			
		||||
- **Hard line breaks**. With this extension enabled newlines in the input
 | 
			
		||||
  translate into line breaks in the output. This extension is off by default.
 | 
			
		||||
 | 
			
		||||
- **Non blocking space**. With this extension enabled spaces preceeded by an backslash n the input
 | 
			
		||||
  translate non-blocking spaces in the output. This extension is off by default.
 | 
			
		||||
 | 
			
		||||
- **Smart quotes**. Smartypants-style punctuation substitution is
 | 
			
		||||
  supported, turning normal double- and single-quote marks into
 | 
			
		||||
  curly quotes, etc.
 | 
			
		||||
 | 
			
		||||
- **LaTeX-style dash parsing** is an additional option, where `--`
 | 
			
		||||
  is translated into `–`, and `---` is translated into
 | 
			
		||||
  `—`. This differs from most smartypants processors, which
 | 
			
		||||
  turn a single hyphen into an ndash and a double hyphen into an
 | 
			
		||||
  mdash.
 | 
			
		||||
 | 
			
		||||
- **Smart fractions**, where anything that looks like a fraction
 | 
			
		||||
  is translated into suitable HTML (instead of just a few special
 | 
			
		||||
  cases like most smartypant processors). For example, `4/5`
 | 
			
		||||
  becomes `<sup>4</sup>⁄<sub>5</sub>`, which renders as
 | 
			
		||||
  <sup>4</sup>⁄<sub>5</sub>.
 | 
			
		||||
 | 
			
		||||
- **MathJaX Support** is an additional feature which is supported by
 | 
			
		||||
  many markdown editor. It translate inline math equation quoted by `$`
 | 
			
		||||
  and display math block quoted by `$$` into MathJax compatible format.
 | 
			
		||||
  hyphen `_` won't break LaTeX render within a math element any more.
 | 
			
		||||
 | 
			
		||||
  ```
 | 
			
		||||
  $$
 | 
			
		||||
  \left[ \begin{array}{a} a^l_1 \\ ⋮ \\ a^l_{d_l} \end{array}\right]
 | 
			
		||||
  = \sigma(
 | 
			
		||||
   \left[ \begin{matrix}
 | 
			
		||||
   	w^l_{1,1} & ⋯  & w^l_{1,d_{l-1}} \\
 | 
			
		||||
   	⋮ & ⋱  & ⋮  \\
 | 
			
		||||
   	w^l_{d_l,1} & ⋯  & w^l_{d_l,d_{l-1}} \\
 | 
			
		||||
   \end{matrix}\right]  ·
 | 
			
		||||
   \left[ \begin{array}{x} a^{l-1}_1 \\ ⋮ \\ ⋮ \\ a^{l-1}_{d_{l-1}} \end{array}\right] +
 | 
			
		||||
   \left[ \begin{array}{b} b^l_1 \\ ⋮ \\ b^l_{d_l} \end{array}\right])
 | 
			
		||||
   $$
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
- **Ordered list start number**. With this extension enabled an ordered list will start with the
 | 
			
		||||
  the number that was used to start it.
 | 
			
		||||
 | 
			
		||||
- **Super and subscript**. With this extension enabled sequences between ^ will indicate
 | 
			
		||||
  superscript and ~ will become a subscript. For example: H~2~O is a liquid, 2^10^ is 1024.
 | 
			
		||||
 | 
			
		||||
- **Block level attributes**, allow setting attributes (ID, classes and key/value pairs) on block
 | 
			
		||||
  level elements. The attribute must be enclosed with braces and be put on a line before the
 | 
			
		||||
  element.
 | 
			
		||||
 | 
			
		||||
  ```
 | 
			
		||||
  {#id3 .myclass fontsize="tiny"}
 | 
			
		||||
  # Header 1
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
  Will convert into `<h1 id="id3" class="myclass" fontsize="tiny">Header 1</h1>`.
 | 
			
		||||
 | 
			
		||||
- **Mmark support**, see <https://mmark.nl/syntax> for all new syntax elements this adds.
 | 
			
		||||
 | 
			
		||||
## Todo
 | 
			
		||||
 | 
			
		||||
- port https://github.com/russross/blackfriday/issues/348
 | 
			
		||||
- port [LaTeX output](https://github.com/Ambrevar/Blackfriday-LaTeX):
 | 
			
		||||
  renders output as LaTeX.
 | 
			
		||||
- port https://github.com/shurcooL/github_flavored_markdown to markdown
 | 
			
		||||
- port [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt,
 | 
			
		||||
  but for markdown.
 | 
			
		||||
- More unit testing
 | 
			
		||||
- Improve unicode support. It does not understand all unicode
 | 
			
		||||
  rules (about what constitutes a letter, a punctuation symbol,
 | 
			
		||||
  etc.), so it may fail to detect word boundaries correctly in
 | 
			
		||||
  some instances. It is safe on all utf-8 input.
 | 
			
		||||
 | 
			
		||||
## History
 | 
			
		||||
 | 
			
		||||
markdown is a fork of v2 of https://github.com/russross/blackfriday that is:
 | 
			
		||||
 | 
			
		||||
- actively maintained (sadly in Feb 2018 blackfriday was inactive for 5 months with many bugs and pull requests accumulated)
 | 
			
		||||
- refactored API (split into ast/parser/html sub-packages)
 | 
			
		||||
 | 
			
		||||
Blackfriday itself was based on C implementation [sundown](https://github.com/vmg/sundown) which in turn was based on [libsoldout](http://fossil.instinctive.eu/libsoldout/home).
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
[Simplified BSD License](LICENSE.txt)
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/gomarkdown/markdown/ast/attribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/gomarkdown/markdown/ast/attribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
package ast
 | 
			
		||||
 | 
			
		||||
// An attribute can be attached to block elements. They are specified as
 | 
			
		||||
// {#id .classs key="value"} where quotes for values are mandatory, multiple
 | 
			
		||||
// key/value pairs are separated by whitespace.
 | 
			
		||||
type Attribute struct {
 | 
			
		||||
	ID      []byte
 | 
			
		||||
	Classes [][]byte
 | 
			
		||||
	Attrs   map[string][]byte
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/gomarkdown/markdown/ast/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/gomarkdown/markdown/ast/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
/*
 | 
			
		||||
Package ast defines tree representation of a parsed markdown document.
 | 
			
		||||
*/
 | 
			
		||||
package ast
 | 
			
		||||
							
								
								
									
										559
									
								
								vendor/github.com/gomarkdown/markdown/ast/node.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										559
									
								
								vendor/github.com/gomarkdown/markdown/ast/node.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,559 @@
 | 
			
		||||
package ast
 | 
			
		||||
 | 
			
		||||
// ListType contains bitwise or'ed flags for list and list item objects.
 | 
			
		||||
type ListType int
 | 
			
		||||
 | 
			
		||||
// These are the possible flag values for the ListItem renderer.
 | 
			
		||||
// Multiple flag values may be ORed together.
 | 
			
		||||
// These are mostly of interest if you are writing a new output format.
 | 
			
		||||
const (
 | 
			
		||||
	ListTypeOrdered ListType = 1 << iota
 | 
			
		||||
	ListTypeDefinition
 | 
			
		||||
	ListTypeTerm
 | 
			
		||||
 | 
			
		||||
	ListItemContainsBlock
 | 
			
		||||
	ListItemBeginningOfList // TODO: figure out if this is of any use now
 | 
			
		||||
	ListItemEndOfList
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CellAlignFlags holds a type of alignment in a table cell.
 | 
			
		||||
type CellAlignFlags int
 | 
			
		||||
 | 
			
		||||
// These are the possible flag values for the table cell renderer.
 | 
			
		||||
// Only a single one of these values will be used; they are not ORed together.
 | 
			
		||||
// These are mostly of interest if you are writing a new output format.
 | 
			
		||||
const (
 | 
			
		||||
	TableAlignmentLeft CellAlignFlags = 1 << iota
 | 
			
		||||
	TableAlignmentRight
 | 
			
		||||
	TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (a CellAlignFlags) String() string {
 | 
			
		||||
	switch a {
 | 
			
		||||
	case TableAlignmentLeft:
 | 
			
		||||
		return "left"
 | 
			
		||||
	case TableAlignmentRight:
 | 
			
		||||
		return "right"
 | 
			
		||||
	case TableAlignmentCenter:
 | 
			
		||||
		return "center"
 | 
			
		||||
	default:
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DocumentMatters holds the type of a {front,main,back}matter in the document
 | 
			
		||||
type DocumentMatters int
 | 
			
		||||
 | 
			
		||||
// These are all possible Document divisions.
 | 
			
		||||
const (
 | 
			
		||||
	DocumentMatterNone DocumentMatters = iota
 | 
			
		||||
	DocumentMatterFront
 | 
			
		||||
	DocumentMatterMain
 | 
			
		||||
	DocumentMatterBack
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CitationTypes holds the type of a citation, informative, normative or suppressed
 | 
			
		||||
type CitationTypes int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CitationTypeNone CitationTypes = iota
 | 
			
		||||
	CitationTypeSuppressed
 | 
			
		||||
	CitationTypeInformative
 | 
			
		||||
	CitationTypeNormative
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Node defines an ast node
 | 
			
		||||
type Node interface {
 | 
			
		||||
	AsContainer() *Container
 | 
			
		||||
	AsLeaf() *Leaf
 | 
			
		||||
	GetParent() Node
 | 
			
		||||
	SetParent(newParent Node)
 | 
			
		||||
	GetChildren() []Node
 | 
			
		||||
	SetChildren(newChildren []Node)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Container is a type of node that can contain children
 | 
			
		||||
type Container struct {
 | 
			
		||||
	Parent   Node
 | 
			
		||||
	Children []Node
 | 
			
		||||
 | 
			
		||||
	Literal []byte // Text contents of the leaf nodes
 | 
			
		||||
	Content []byte // Markdown content of the block nodes
 | 
			
		||||
 | 
			
		||||
	*Attribute // Block level attribute
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AsContainer returns itself as *Container
 | 
			
		||||
func (c *Container) AsContainer() *Container {
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AsLeaf returns nil
 | 
			
		||||
func (c *Container) AsLeaf() *Leaf {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetParent returns parent node
 | 
			
		||||
func (c *Container) GetParent() Node {
 | 
			
		||||
	return c.Parent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetParent sets the parent node
 | 
			
		||||
func (c *Container) SetParent(newParent Node) {
 | 
			
		||||
	c.Parent = newParent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetChildren returns children nodes
 | 
			
		||||
func (c *Container) GetChildren() []Node {
 | 
			
		||||
	return c.Children
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetChildren sets children node
 | 
			
		||||
func (c *Container) SetChildren(newChildren []Node) {
 | 
			
		||||
	c.Children = newChildren
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Leaf is a type of node that cannot have children
 | 
			
		||||
type Leaf struct {
 | 
			
		||||
	Parent Node
 | 
			
		||||
 | 
			
		||||
	Literal []byte // Text contents of the leaf nodes
 | 
			
		||||
	Content []byte // Markdown content of the block nodes
 | 
			
		||||
 | 
			
		||||
	*Attribute // Block level attribute
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AsContainer returns nil
 | 
			
		||||
func (l *Leaf) AsContainer() *Container {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AsLeaf returns itself as *Leaf
 | 
			
		||||
func (l *Leaf) AsLeaf() *Leaf {
 | 
			
		||||
	return l
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetParent returns parent node
 | 
			
		||||
func (l *Leaf) GetParent() Node {
 | 
			
		||||
	return l.Parent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetParent sets the parent nodd
 | 
			
		||||
func (l *Leaf) SetParent(newParent Node) {
 | 
			
		||||
	l.Parent = newParent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetChildren returns nil because Leaf cannot have children
 | 
			
		||||
func (l *Leaf) GetChildren() []Node {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetChildren will panic becuase Leaf cannot have children
 | 
			
		||||
func (l *Leaf) SetChildren(newChildren []Node) {
 | 
			
		||||
	panic("leaf node cannot have children")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Document represents markdown document node, a root of ast
 | 
			
		||||
type Document struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DocumentMatter represents markdown node that signals a document
 | 
			
		||||
// division: frontmatter, mainmatter or backmatter.
 | 
			
		||||
type DocumentMatter struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	Matter DocumentMatters
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BlockQuote represents markdown block quote node
 | 
			
		||||
type BlockQuote struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Aside represents an markdown aside node.
 | 
			
		||||
type Aside struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List represents markdown list node
 | 
			
		||||
type List struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	ListFlags       ListType
 | 
			
		||||
	Tight           bool   // Skip <p>s around list item data if true
 | 
			
		||||
	BulletChar      byte   // '*', '+' or '-' in bullet lists
 | 
			
		||||
	Delimiter       byte   // '.' or ')' after the number in ordered lists
 | 
			
		||||
	Start           int    // for ordered lists this indicates the starting number if > 0
 | 
			
		||||
	RefLink         []byte // If not nil, turns this list item into a footnote item and triggers different rendering
 | 
			
		||||
	IsFootnotesList bool   // This is a list of footnotes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListItem represents markdown list item node
 | 
			
		||||
type ListItem struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	ListFlags       ListType
 | 
			
		||||
	Tight           bool   // Skip <p>s around list item data if true
 | 
			
		||||
	BulletChar      byte   // '*', '+' or '-' in bullet lists
 | 
			
		||||
	Delimiter       byte   // '.' or ')' after the number in ordered lists
 | 
			
		||||
	RefLink         []byte // If not nil, turns this list item into a footnote item and triggers different rendering
 | 
			
		||||
	IsFootnotesList bool   // This is a list of footnotes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Paragraph represents markdown paragraph node
 | 
			
		||||
type Paragraph struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Math represents markdown MathAjax inline node
 | 
			
		||||
type Math struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MathBlock represents markdown MathAjax block node
 | 
			
		||||
type MathBlock struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Heading represents markdown heading node
 | 
			
		||||
type Heading struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	Level        int    // This holds the heading level number
 | 
			
		||||
	HeadingID    string // This might hold heading ID, if present
 | 
			
		||||
	IsTitleblock bool   // Specifies whether it's a title block
 | 
			
		||||
	IsSpecial    bool   // We are a special heading (starts with .#)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HorizontalRule represents markdown horizontal rule node
 | 
			
		||||
type HorizontalRule struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Emph represents markdown emphasis node
 | 
			
		||||
type Emph struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Strong represents markdown strong node
 | 
			
		||||
type Strong struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Del represents markdown del node
 | 
			
		||||
type Del struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Link represents markdown link node
 | 
			
		||||
type Link struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	Destination []byte // Destination is what goes into a href
 | 
			
		||||
	Title       []byte // Title is the tooltip thing that goes in a title attribute
 | 
			
		||||
	NoteID      int    // NoteID contains a serial number of a footnote, zero if it's not a footnote
 | 
			
		||||
	Footnote    Node   // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
 | 
			
		||||
	DeferredID  []byte // If a deferred link this holds the original ID.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CrossReference is a reference node.
 | 
			
		||||
type CrossReference struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	Destination []byte // Destination is where the reference points to
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Citation is a citation node.
 | 
			
		||||
type Citation struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
 | 
			
		||||
	Destination [][]byte        // Destination is where the citation points to. Multiple ones are allowed.
 | 
			
		||||
	Type        []CitationTypes // 1:1 mapping of destination and citation type
 | 
			
		||||
	Suffix      [][]byte        // Potential citation suffix, i.e. [@!RFC1035, p. 144]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Image represents markdown image node
 | 
			
		||||
type Image struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	Destination []byte // Destination is what goes into a href
 | 
			
		||||
	Title       []byte // Title is the tooltip thing that goes in a title attribute
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Text represents markdown text node
 | 
			
		||||
type Text struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HTMLBlock represents markdown html node
 | 
			
		||||
type HTMLBlock struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CodeBlock represents markdown code block node
 | 
			
		||||
type CodeBlock struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
 | 
			
		||||
	IsFenced    bool   // Specifies whether it's a fenced code block or an indented one
 | 
			
		||||
	Info        []byte // This holds the info string
 | 
			
		||||
	FenceChar   byte
 | 
			
		||||
	FenceLength int
 | 
			
		||||
	FenceOffset int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Softbreak represents markdown softbreak node
 | 
			
		||||
// Note: not used currently
 | 
			
		||||
type Softbreak struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hardbreak represents markdown hard break node
 | 
			
		||||
type Hardbreak struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NonBlockingSpace represents markdown non-blocking space node
 | 
			
		||||
type NonBlockingSpace struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Code represents markdown code node
 | 
			
		||||
type Code struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HTMLSpan represents markdown html span node
 | 
			
		||||
type HTMLSpan struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Table represents markdown table node
 | 
			
		||||
type Table struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TableCell represents markdown table cell node
 | 
			
		||||
type TableCell struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	IsHeader bool           // This tells if it's under the header row
 | 
			
		||||
	Align    CellAlignFlags // This holds the value for align attribute
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TableHeader represents markdown table head node
 | 
			
		||||
type TableHeader struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TableBody represents markdown table body node
 | 
			
		||||
type TableBody struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TableRow represents markdown table row node
 | 
			
		||||
type TableRow struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TableFooter represents markdown table foot node
 | 
			
		||||
type TableFooter struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Caption represents a figure, code or quote caption
 | 
			
		||||
type Caption struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CaptionFigure is a node (blockquote or codeblock) that has a caption
 | 
			
		||||
type CaptionFigure struct {
 | 
			
		||||
	Container
 | 
			
		||||
 | 
			
		||||
	HeadingID string // This might hold heading ID, if present
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Callout is a node that can exist both in text (where it is an actual node) and in a code block.
 | 
			
		||||
type Callout struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
 | 
			
		||||
	ID []byte // number of this callout
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Index is a node that contains an Index item and an optional, subitem.
 | 
			
		||||
type Index struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
 | 
			
		||||
	Primary bool
 | 
			
		||||
	Item    []byte
 | 
			
		||||
	Subitem []byte
 | 
			
		||||
	ID      string // ID of the index
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subscript is a subscript node
 | 
			
		||||
type Subscript struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subscript is a superscript node
 | 
			
		||||
type Superscript struct {
 | 
			
		||||
	Leaf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Footnotes is a node that contains all footnotes
 | 
			
		||||
type Footnotes struct {
 | 
			
		||||
	Container
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeNodeFromArray(a []Node, node Node) []Node {
 | 
			
		||||
	n := len(a)
 | 
			
		||||
	for i := 0; i < n; i++ {
 | 
			
		||||
		if a[i] == node {
 | 
			
		||||
			return append(a[:i], a[i+1:]...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AppendChild appends child to children of parent
 | 
			
		||||
// It panics if either node is nil.
 | 
			
		||||
func AppendChild(parent Node, child Node) {
 | 
			
		||||
	RemoveFromTree(child)
 | 
			
		||||
	child.SetParent(parent)
 | 
			
		||||
	newChildren := append(parent.GetChildren(), child)
 | 
			
		||||
	parent.SetChildren(newChildren)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveFromTree removes this node from tree
 | 
			
		||||
func RemoveFromTree(n Node) {
 | 
			
		||||
	if n.GetParent() == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// important: don't clear n.Children if n has no parent
 | 
			
		||||
	// we're called from AppendChild and that might happen on a node
 | 
			
		||||
	// that accumulated Children but hasn't been inserted into the tree
 | 
			
		||||
	n.SetChildren(nil)
 | 
			
		||||
	p := n.GetParent()
 | 
			
		||||
	newChildren := removeNodeFromArray(p.GetChildren(), n)
 | 
			
		||||
	if newChildren != nil {
 | 
			
		||||
		p.SetChildren(newChildren)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLastChild returns last child of node n
 | 
			
		||||
// It's implemented as stand-alone function to keep Node interface small
 | 
			
		||||
func GetLastChild(n Node) Node {
 | 
			
		||||
	a := n.GetChildren()
 | 
			
		||||
	if len(a) > 0 {
 | 
			
		||||
		return a[len(a)-1]
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetFirstChild returns first child of node n
 | 
			
		||||
// It's implemented as stand-alone function to keep Node interface small
 | 
			
		||||
func GetFirstChild(n Node) Node {
 | 
			
		||||
	a := n.GetChildren()
 | 
			
		||||
	if len(a) > 0 {
 | 
			
		||||
		return a[0]
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetNextNode returns next sibling of node n (node after n)
 | 
			
		||||
// We can't make it part of Container or Leaf because we loose Node identity
 | 
			
		||||
func GetNextNode(n Node) Node {
 | 
			
		||||
	parent := n.GetParent()
 | 
			
		||||
	if parent == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	a := parent.GetChildren()
 | 
			
		||||
	len := len(a) - 1
 | 
			
		||||
	for i := 0; i < len; i++ {
 | 
			
		||||
		if a[i] == n {
 | 
			
		||||
			return a[i+1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPrevNode returns previous sibling of node n (node before n)
 | 
			
		||||
// We can't make it part of Container or Leaf because we loose Node identity
 | 
			
		||||
func GetPrevNode(n Node) Node {
 | 
			
		||||
	parent := n.GetParent()
 | 
			
		||||
	if parent == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	a := parent.GetChildren()
 | 
			
		||||
	len := len(a)
 | 
			
		||||
	for i := 1; i < len; i++ {
 | 
			
		||||
		if a[i] == n {
 | 
			
		||||
			return a[i-1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WalkStatus allows NodeVisitor to have some control over the tree traversal.
 | 
			
		||||
// It is returned from NodeVisitor and different values allow Node.Walk to
 | 
			
		||||
// decide which node to go to next.
 | 
			
		||||
type WalkStatus int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// GoToNext is the default traversal of every node.
 | 
			
		||||
	GoToNext WalkStatus = iota
 | 
			
		||||
	// SkipChildren tells walker to skip all children of current node.
 | 
			
		||||
	SkipChildren
 | 
			
		||||
	// Terminate tells walker to terminate the traversal.
 | 
			
		||||
	Terminate
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NodeVisitor is a callback to be called when traversing the syntax tree.
 | 
			
		||||
// Called twice for every node: once with entering=true when the branch is
 | 
			
		||||
// first visited, then with entering=false after all the children are done.
 | 
			
		||||
type NodeVisitor interface {
 | 
			
		||||
	Visit(node Node, entering bool) WalkStatus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NodeVisitorFunc casts a function to match NodeVisitor interface
 | 
			
		||||
type NodeVisitorFunc func(node Node, entering bool) WalkStatus
 | 
			
		||||
 | 
			
		||||
// Walk traverses tree recursively
 | 
			
		||||
func Walk(n Node, visitor NodeVisitor) WalkStatus {
 | 
			
		||||
	isContainer := n.AsContainer() != nil
 | 
			
		||||
	status := visitor.Visit(n, true) // entering
 | 
			
		||||
	if status == Terminate {
 | 
			
		||||
		// even if terminating, close container node
 | 
			
		||||
		if isContainer {
 | 
			
		||||
			visitor.Visit(n, false)
 | 
			
		||||
		}
 | 
			
		||||
		return status
 | 
			
		||||
	}
 | 
			
		||||
	if isContainer && status != SkipChildren {
 | 
			
		||||
		children := n.GetChildren()
 | 
			
		||||
		for _, n := range children {
 | 
			
		||||
			status = Walk(n, visitor)
 | 
			
		||||
			if status == Terminate {
 | 
			
		||||
				return status
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if isContainer {
 | 
			
		||||
		status = visitor.Visit(n, false) // exiting
 | 
			
		||||
		if status == Terminate {
 | 
			
		||||
			return status
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return GoToNext
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Visit calls visitor function
 | 
			
		||||
func (f NodeVisitorFunc) Visit(node Node, entering bool) WalkStatus {
 | 
			
		||||
	return f(node, entering)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WalkFunc is like Walk but accepts just a callback function
 | 
			
		||||
func WalkFunc(n Node, f NodeVisitorFunc) {
 | 
			
		||||
	visitor := NodeVisitorFunc(f)
 | 
			
		||||
	Walk(n, visitor)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										165
									
								
								vendor/github.com/gomarkdown/markdown/ast/print.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								vendor/github.com/gomarkdown/markdown/ast/print.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
			
		||||
package ast
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Print is for debugging. It prints a string representation of parsed
 | 
			
		||||
// markdown doc (result of parser.Parse()) to dst.
 | 
			
		||||
//
 | 
			
		||||
// To make output readable, it shortens text output.
 | 
			
		||||
func Print(dst io.Writer, doc Node) {
 | 
			
		||||
	PrintWithPrefix(dst, doc, "  ")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PrintWithPrefix is like Print but allows customizing prefix used for
 | 
			
		||||
// indentation. By default it's 2 spaces. You can change it to e.g. tab
 | 
			
		||||
// by passing "\t"
 | 
			
		||||
func PrintWithPrefix(w io.Writer, doc Node, prefix string) {
 | 
			
		||||
	// for more compact output, don't print outer Document
 | 
			
		||||
	if _, ok := doc.(*Document); ok {
 | 
			
		||||
		for _, c := range doc.GetChildren() {
 | 
			
		||||
			printRecur(w, c, prefix, 0)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		printRecur(w, doc, prefix, 0)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToString is like Dump but returns result as a string
 | 
			
		||||
func ToString(doc Node) string {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	Print(&buf, doc)
 | 
			
		||||
	return buf.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func contentToString(d1 []byte, d2 []byte) string {
 | 
			
		||||
	if d1 != nil {
 | 
			
		||||
		return string(d1)
 | 
			
		||||
	}
 | 
			
		||||
	if d2 != nil {
 | 
			
		||||
		return string(d2)
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getContent(node Node) string {
 | 
			
		||||
	if c := node.AsContainer(); c != nil {
 | 
			
		||||
		return contentToString(c.Literal, c.Content)
 | 
			
		||||
	}
 | 
			
		||||
	leaf := node.AsLeaf()
 | 
			
		||||
	return contentToString(leaf.Literal, leaf.Content)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func shortenString(s string, maxLen int) string {
 | 
			
		||||
	// for cleaner, one-line ouput, replace some white-space chars
 | 
			
		||||
	// with their escaped version
 | 
			
		||||
	s = strings.Replace(s, "\n", `\n`, -1)
 | 
			
		||||
	s = strings.Replace(s, "\r", `\r`, -1)
 | 
			
		||||
	s = strings.Replace(s, "\t", `\t`, -1)
 | 
			
		||||
	if maxLen < 0 {
 | 
			
		||||
		return s
 | 
			
		||||
	}
 | 
			
		||||
	if len(s) < maxLen {
 | 
			
		||||
		return s
 | 
			
		||||
	}
 | 
			
		||||
	// add "..." to indicate truncation
 | 
			
		||||
	return s[:maxLen-3] + "..."
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// get a short name of the type of v which excludes package name
 | 
			
		||||
// and strips "()" from the end
 | 
			
		||||
func getNodeType(node Node) string {
 | 
			
		||||
	s := fmt.Sprintf("%T", node)
 | 
			
		||||
	s = strings.TrimSuffix(s, "()")
 | 
			
		||||
	if idx := strings.Index(s, "."); idx != -1 {
 | 
			
		||||
		return s[idx+1:]
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printDefault(w io.Writer, indent string, typeName string, content string) {
 | 
			
		||||
	content = strings.TrimSpace(content)
 | 
			
		||||
	if len(content) > 0 {
 | 
			
		||||
		fmt.Fprintf(w, "%s%s '%s'\n", indent, typeName, content)
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Fprintf(w, "%s%s\n", indent, typeName)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getListFlags(f ListType) string {
 | 
			
		||||
	var s string
 | 
			
		||||
	if f&ListTypeOrdered != 0 {
 | 
			
		||||
		s += "ordered "
 | 
			
		||||
	}
 | 
			
		||||
	if f&ListTypeDefinition != 0 {
 | 
			
		||||
		s += "definition "
 | 
			
		||||
	}
 | 
			
		||||
	if f&ListTypeTerm != 0 {
 | 
			
		||||
		s += "term "
 | 
			
		||||
	}
 | 
			
		||||
	if f&ListItemContainsBlock != 0 {
 | 
			
		||||
		s += "has_block "
 | 
			
		||||
	}
 | 
			
		||||
	if f&ListItemBeginningOfList != 0 {
 | 
			
		||||
		s += "start "
 | 
			
		||||
	}
 | 
			
		||||
	if f&ListItemEndOfList != 0 {
 | 
			
		||||
		s += "end "
 | 
			
		||||
	}
 | 
			
		||||
	s = strings.TrimSpace(s)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printRecur(w io.Writer, node Node, prefix string, depth int) {
 | 
			
		||||
	if node == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	indent := strings.Repeat(prefix, depth)
 | 
			
		||||
 | 
			
		||||
	content := shortenString(getContent(node), 40)
 | 
			
		||||
	typeName := getNodeType(node)
 | 
			
		||||
	switch v := node.(type) {
 | 
			
		||||
	case *Link:
 | 
			
		||||
		content := "url=" + string(v.Destination)
 | 
			
		||||
		printDefault(w, indent, typeName, content)
 | 
			
		||||
	case *Image:
 | 
			
		||||
		content := "url=" + string(v.Destination)
 | 
			
		||||
		printDefault(w, indent, typeName, content)
 | 
			
		||||
	case *List:
 | 
			
		||||
		if v.Start > 1 {
 | 
			
		||||
			content += fmt.Sprintf("start=%d ", v.Start)
 | 
			
		||||
		}
 | 
			
		||||
		if v.Tight {
 | 
			
		||||
			content += "tight "
 | 
			
		||||
		}
 | 
			
		||||
		if v.IsFootnotesList {
 | 
			
		||||
			content += "footnotes "
 | 
			
		||||
		}
 | 
			
		||||
		flags := getListFlags(v.ListFlags)
 | 
			
		||||
		if len(flags) > 0 {
 | 
			
		||||
			content += "flags=" + flags + " "
 | 
			
		||||
		}
 | 
			
		||||
		printDefault(w, indent, typeName, content)
 | 
			
		||||
	case *ListItem:
 | 
			
		||||
		if v.Tight {
 | 
			
		||||
			content += "tight "
 | 
			
		||||
		}
 | 
			
		||||
		if v.IsFootnotesList {
 | 
			
		||||
			content += "footnotes "
 | 
			
		||||
		}
 | 
			
		||||
		flags := getListFlags(v.ListFlags)
 | 
			
		||||
		if len(flags) > 0 {
 | 
			
		||||
			content += "flags=" + flags + " "
 | 
			
		||||
		}
 | 
			
		||||
		printDefault(w, indent, typeName, content)
 | 
			
		||||
	default:
 | 
			
		||||
		printDefault(w, indent, typeName, content)
 | 
			
		||||
	}
 | 
			
		||||
	for _, child := range node.GetChildren() {
 | 
			
		||||
		printRecur(w, child, prefix, depth+1)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/github.com/gomarkdown/markdown/changes-from-blackfriday.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/gomarkdown/markdown/changes-from-blackfriday.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
## Changes from blackfriday
 | 
			
		||||
 | 
			
		||||
This library is derived from blackfriday library. Here's a list of changes.
 | 
			
		||||
 | 
			
		||||
**Redesigned API**
 | 
			
		||||
 | 
			
		||||
- split into 3 separate packages: ast, parser and html (for html renderer). This makes the API more manageable. It also separates e.g. parser option from renderer options
 | 
			
		||||
- changed how AST node is represented from union-like representation (manually keeping track of the type of the node) to using interface{} (which is a Go way to combine an arbitrary value with its type)
 | 
			
		||||
 | 
			
		||||
**Allow re-using most of html renderer logic**
 | 
			
		||||
 | 
			
		||||
You can implement your own renderer by implementing `Renderer` interface.
 | 
			
		||||
 | 
			
		||||
Implementing a full renderer is a lot of work and often you just want to tweak html rendering of few node typs.
 | 
			
		||||
 | 
			
		||||
I've added a way to hook `Renderer.Render` function in html renderer with a custom function that can take over rendering of specific nodes.
 | 
			
		||||
 | 
			
		||||
I use it myself to do syntax-highlighting of code snippets.
 | 
			
		||||
 | 
			
		||||
**Speed up go test**
 | 
			
		||||
 | 
			
		||||
Running `go test` was really slow (17 secs) because it did a poor man's version of fuzzing by feeding the parser all subsets of test strings in order to find panics
 | 
			
		||||
due to incorrect parsing logic.
 | 
			
		||||
 | 
			
		||||
I've moved that logic to `cmd/crashtest`, so that it can be run on CI but not slow down regular development.
 | 
			
		||||
 | 
			
		||||
Now `go test` is blazing fast.
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/gomarkdown/markdown/codecov.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/gomarkdown/markdown/codecov.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
coverage:
 | 
			
		||||
  status:
 | 
			
		||||
    project:
 | 
			
		||||
      default:
 | 
			
		||||
        # basic
 | 
			
		||||
        target: 60%
 | 
			
		||||
        threshold: 2%
 | 
			
		||||
        base: auto
 | 
			
		||||
							
								
								
									
										35
									
								
								vendor/github.com/gomarkdown/markdown/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/gomarkdown/markdown/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
Package markdown implements markdown parser and HTML renderer.
 | 
			
		||||
 | 
			
		||||
It parses markdown into AST format which can be serialized to HTML
 | 
			
		||||
(using html.Renderer) or possibly other formats (using alternate renderers).
 | 
			
		||||
 | 
			
		||||
Convert markdown to HTML
 | 
			
		||||
 | 
			
		||||
The simplest way to convert markdown document to HTML
 | 
			
		||||
 | 
			
		||||
  md := []byte("## markdown document")
 | 
			
		||||
  html := markdown.ToHTML(md, nil, nil)
 | 
			
		||||
 | 
			
		||||
Customizing parsing and HTML rendering
 | 
			
		||||
 | 
			
		||||
You can customize parser and HTML renderer:
 | 
			
		||||
 | 
			
		||||
	import (
 | 
			
		||||
		"github.com/gomarkdown/markdown/parser"
 | 
			
		||||
		"github.com/gomarkdown/markdown/renderer"
 | 
			
		||||
		"github.com/gomarkdown/markdown"
 | 
			
		||||
	)
 | 
			
		||||
	extensions := parser.CommonExtensions | parser.AutoHeadingIDs
 | 
			
		||||
	p := parser.NewWithExensions(extensions)
 | 
			
		||||
 | 
			
		||||
	htmlFlags := html.CommonFlags | html.HrefTargetBlank
 | 
			
		||||
	opts := html.RendererOptions{Flags: htmlFlags}
 | 
			
		||||
	renderer := html.NewRenderer(opts)
 | 
			
		||||
 | 
			
		||||
	md := []byte("markdown text")
 | 
			
		||||
	html := markdown.ToHTML(md, p, renderer)
 | 
			
		||||
 | 
			
		||||
For a cmd-line tool see https://github.com/gomarkdown/mdtohtml
 | 
			
		||||
*/
 | 
			
		||||
package markdown
 | 
			
		||||
							
								
								
									
										9
									
								
								vendor/github.com/gomarkdown/markdown/fuzz.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/gomarkdown/markdown/fuzz.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
// +build gofuzz
 | 
			
		||||
 | 
			
		||||
package markdown
 | 
			
		||||
 | 
			
		||||
// Fuzz is to be used by https://github.com/dvyukov/go-fuzz
 | 
			
		||||
func Fuzz(data []byte) int {
 | 
			
		||||
	Parse(data, nil)
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/gomarkdown/markdown/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/gomarkdown/markdown/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
module github.com/gomarkdown/markdown
 | 
			
		||||
 | 
			
		||||
go 1.12
 | 
			
		||||
 | 
			
		||||
require golang.org/dl v0.0.0-20190829154251-82a15e2f2ead // indirect
 | 
			
		||||
							
								
								
									
										42
									
								
								vendor/github.com/gomarkdown/markdown/html/callouts.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/gomarkdown/markdown/html/callouts.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
package html
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
	"github.com/gomarkdown/markdown/parser"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// EscapeHTMLCallouts writes html-escaped d to w. It escapes &, <, > and " characters, *but*
 | 
			
		||||
// expands callouts <<N>> with the callout HTML, i.e. by calling r.callout() with a newly created
 | 
			
		||||
// ast.Callout node.
 | 
			
		||||
func (r *Renderer) EscapeHTMLCallouts(w io.Writer, d []byte) {
 | 
			
		||||
	ld := len(d)
 | 
			
		||||
Parse:
 | 
			
		||||
	for i := 0; i < ld; i++ {
 | 
			
		||||
		for _, comment := range r.opts.Comments {
 | 
			
		||||
			if !bytes.HasPrefix(d[i:], comment) {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			lc := len(comment)
 | 
			
		||||
			if i+lc < ld {
 | 
			
		||||
				if id, consumed := parser.IsCallout(d[i+lc:]); consumed > 0 {
 | 
			
		||||
					// We have seen a callout
 | 
			
		||||
					callout := &ast.Callout{ID: id}
 | 
			
		||||
					r.callout(w, callout)
 | 
			
		||||
					i += consumed + lc - 1
 | 
			
		||||
					continue Parse
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		escSeq := Escaper[d[i]]
 | 
			
		||||
		if escSeq != nil {
 | 
			
		||||
			w.Write(escSeq)
 | 
			
		||||
		} else {
 | 
			
		||||
			w.Write([]byte{d[i]})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/gomarkdown/markdown/html/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/gomarkdown/markdown/html/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
Package html implements HTML renderer of parsed markdown document.
 | 
			
		||||
 | 
			
		||||
Configuring and customizing a renderer
 | 
			
		||||
 | 
			
		||||
A renderer can be configured with multiple options:
 | 
			
		||||
 | 
			
		||||
	import "github.com/gomarkdown/markdown/html"
 | 
			
		||||
 | 
			
		||||
	flags := html.CommonFlags | html.CompletePage | html.HrefTargetBlank
 | 
			
		||||
	opts := html.RenderOptions{
 | 
			
		||||
		TItle: "A custom title",
 | 
			
		||||
		Flags: flags,
 | 
			
		||||
	}
 | 
			
		||||
	renderer := html.NewRenderer(opts)
 | 
			
		||||
 | 
			
		||||
You can also re-use most of the logic and customize rendering of selected nodes
 | 
			
		||||
by providing node render hook.
 | 
			
		||||
This is most useful for rendering nodes that allow for design choices, like
 | 
			
		||||
links or code blocks.
 | 
			
		||||
 | 
			
		||||
	import (
 | 
			
		||||
		"github.com/gomarkdown/markdown/html"
 | 
			
		||||
		"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// a very dummy render hook that will output "code_replacements" instead of
 | 
			
		||||
	// <code>${content}</code> emitted by html.Renderer
 | 
			
		||||
	func renderHookCodeBlock(w io.Writer, node *ast.Node, entering bool) (ast.WalkStatus, bool) {
 | 
			
		||||
		_, ok := node.Data.(*ast.CodeBlockData)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return ast.GoToNext, false
 | 
			
		||||
		}
 | 
			
		||||
		io.WriteString(w, "code_replacement")
 | 
			
		||||
		return ast.GoToNext, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	opts := html.RendererOptions{
 | 
			
		||||
		RenderNodeHook: renderHookCodeBlock,
 | 
			
		||||
	}
 | 
			
		||||
	renderer := html.NewRenderer(opts)
 | 
			
		||||
*/
 | 
			
		||||
package html
 | 
			
		||||
							
								
								
									
										50
									
								
								vendor/github.com/gomarkdown/markdown/html/esc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								vendor/github.com/gomarkdown/markdown/html/esc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
package html
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"html"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var Escaper = [256][]byte{
 | 
			
		||||
	'&': []byte("&"),
 | 
			
		||||
	'<': []byte("<"),
 | 
			
		||||
	'>': []byte(">"),
 | 
			
		||||
	'"': []byte("""),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EscapeHTML writes html-escaped d to w. It escapes &, <, > and " characters.
 | 
			
		||||
func EscapeHTML(w io.Writer, d []byte) {
 | 
			
		||||
	var start, end int
 | 
			
		||||
	n := len(d)
 | 
			
		||||
	for end < n {
 | 
			
		||||
		escSeq := Escaper[d[end]]
 | 
			
		||||
		if escSeq != nil {
 | 
			
		||||
			w.Write(d[start:end])
 | 
			
		||||
			w.Write(escSeq)
 | 
			
		||||
			start = end + 1
 | 
			
		||||
		}
 | 
			
		||||
		end++
 | 
			
		||||
	}
 | 
			
		||||
	if start < n && end <= n {
 | 
			
		||||
		w.Write(d[start:end])
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func escLink(w io.Writer, text []byte) {
 | 
			
		||||
	unesc := html.UnescapeString(string(text))
 | 
			
		||||
	EscapeHTML(w, []byte(unesc))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Escape writes the text to w, but skips the escape character.
 | 
			
		||||
func Escape(w io.Writer, text []byte) {
 | 
			
		||||
	esc := false
 | 
			
		||||
	for i := 0; i < len(text); i++ {
 | 
			
		||||
		if text[i] == '\\' {
 | 
			
		||||
			esc = !esc
 | 
			
		||||
		}
 | 
			
		||||
		if esc && text[i] == '\\' {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		w.Write([]byte{text[i]})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1318
									
								
								vendor/github.com/gomarkdown/markdown/html/renderer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1318
									
								
								vendor/github.com/gomarkdown/markdown/html/renderer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										444
									
								
								vendor/github.com/gomarkdown/markdown/html/smartypants.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								vendor/github.com/gomarkdown/markdown/html/smartypants.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,444 @@
 | 
			
		||||
package html
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SmartyPants rendering
 | 
			
		||||
 | 
			
		||||
// SPRenderer is a struct containing state of a Smartypants renderer.
 | 
			
		||||
type SPRenderer struct {
 | 
			
		||||
	inSingleQuote bool
 | 
			
		||||
	inDoubleQuote bool
 | 
			
		||||
	callbacks     [256]smartCallback
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wordBoundary(c byte) bool {
 | 
			
		||||
	return c == 0 || isSpace(c) || isPunctuation(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func tolower(c byte) byte {
 | 
			
		||||
	if c >= 'A' && c <= 'Z' {
 | 
			
		||||
		return c - 'A' + 'a'
 | 
			
		||||
	}
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isdigit(c byte) bool {
 | 
			
		||||
	return c >= '0' && c <= '9'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool, addNBSP bool) bool {
 | 
			
		||||
	// edge of the buffer is likely to be a tag that we don't get to see,
 | 
			
		||||
	// so we treat it like text sometimes
 | 
			
		||||
 | 
			
		||||
	// enumerate all sixteen possibilities for (previousChar, nextChar)
 | 
			
		||||
	// each can be one of {0, space, punct, other}
 | 
			
		||||
	switch {
 | 
			
		||||
	case previousChar == 0 && nextChar == 0:
 | 
			
		||||
		// context is not any help here, so toggle
 | 
			
		||||
		*isOpen = !*isOpen
 | 
			
		||||
	case isSpace(previousChar) && nextChar == 0:
 | 
			
		||||
		// [ "] might be [ "<code>foo...]
 | 
			
		||||
		*isOpen = true
 | 
			
		||||
	case isPunctuation(previousChar) && nextChar == 0:
 | 
			
		||||
		// [!"] hmm... could be [Run!"] or [("<code>...]
 | 
			
		||||
		*isOpen = false
 | 
			
		||||
	case /* isnormal(previousChar) && */ nextChar == 0:
 | 
			
		||||
		// [a"] is probably a close
 | 
			
		||||
		*isOpen = false
 | 
			
		||||
	case previousChar == 0 && isSpace(nextChar):
 | 
			
		||||
		// [" ] might be [...foo</code>" ]
 | 
			
		||||
		*isOpen = false
 | 
			
		||||
	case isSpace(previousChar) && isSpace(nextChar):
 | 
			
		||||
		// [ " ] context is not any help here, so toggle
 | 
			
		||||
		*isOpen = !*isOpen
 | 
			
		||||
	case isPunctuation(previousChar) && isSpace(nextChar):
 | 
			
		||||
		// [!" ] is probably a close
 | 
			
		||||
		*isOpen = false
 | 
			
		||||
	case /* isnormal(previousChar) && */ isSpace(nextChar):
 | 
			
		||||
		// [a" ] this is one of the easy cases
 | 
			
		||||
		*isOpen = false
 | 
			
		||||
	case previousChar == 0 && isPunctuation(nextChar):
 | 
			
		||||
		// ["!] hmm... could be ["$1.95] or [</code>"!...]
 | 
			
		||||
		*isOpen = false
 | 
			
		||||
	case isSpace(previousChar) && isPunctuation(nextChar):
 | 
			
		||||
		// [ "!] looks more like [ "$1.95]
 | 
			
		||||
		*isOpen = true
 | 
			
		||||
	case isPunctuation(previousChar) && isPunctuation(nextChar):
 | 
			
		||||
		// [!"!] context is not any help here, so toggle
 | 
			
		||||
		*isOpen = !*isOpen
 | 
			
		||||
	case /* isnormal(previousChar) && */ isPunctuation(nextChar):
 | 
			
		||||
		// [a"!] is probably a close
 | 
			
		||||
		*isOpen = false
 | 
			
		||||
	case previousChar == 0 /* && isnormal(nextChar) */ :
 | 
			
		||||
		// ["a] is probably an open
 | 
			
		||||
		*isOpen = true
 | 
			
		||||
	case isSpace(previousChar) /* && isnormal(nextChar) */ :
 | 
			
		||||
		// [ "a] this is one of the easy cases
 | 
			
		||||
		*isOpen = true
 | 
			
		||||
	case isPunctuation(previousChar) /* && isnormal(nextChar) */ :
 | 
			
		||||
		// [!"a] is probably an open
 | 
			
		||||
		*isOpen = true
 | 
			
		||||
	default:
 | 
			
		||||
		// [a'b] maybe a contraction?
 | 
			
		||||
		*isOpen = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Note that with the limited lookahead, this non-breaking
 | 
			
		||||
	// space will also be appended to single double quotes.
 | 
			
		||||
	if addNBSP && !*isOpen {
 | 
			
		||||
		out.WriteString(" ")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte('&')
 | 
			
		||||
	if *isOpen {
 | 
			
		||||
		out.WriteByte('l')
 | 
			
		||||
	} else {
 | 
			
		||||
		out.WriteByte('r')
 | 
			
		||||
	}
 | 
			
		||||
	out.WriteByte(quote)
 | 
			
		||||
	out.WriteString("quo;")
 | 
			
		||||
 | 
			
		||||
	if addNBSP && *isOpen {
 | 
			
		||||
		out.WriteString(" ")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	if len(text) >= 2 {
 | 
			
		||||
		t1 := tolower(text[1])
 | 
			
		||||
 | 
			
		||||
		if t1 == '\'' {
 | 
			
		||||
			nextChar := byte(0)
 | 
			
		||||
			if len(text) >= 3 {
 | 
			
		||||
				nextChar = text[2]
 | 
			
		||||
			}
 | 
			
		||||
			if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) {
 | 
			
		||||
				return 1
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) {
 | 
			
		||||
			out.WriteString("’")
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(text) >= 3 {
 | 
			
		||||
			t2 := tolower(text[2])
 | 
			
		||||
 | 
			
		||||
			if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) &&
 | 
			
		||||
				(len(text) < 4 || wordBoundary(text[3])) {
 | 
			
		||||
				out.WriteString("’")
 | 
			
		||||
				return 0
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nextChar := byte(0)
 | 
			
		||||
	if len(text) > 1 {
 | 
			
		||||
		nextChar = text[1]
 | 
			
		||||
	}
 | 
			
		||||
	if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote, false) {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte(text[0])
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	if len(text) >= 3 {
 | 
			
		||||
		t1 := tolower(text[1])
 | 
			
		||||
		t2 := tolower(text[2])
 | 
			
		||||
 | 
			
		||||
		if t1 == 'c' && t2 == ')' {
 | 
			
		||||
			out.WriteString("©")
 | 
			
		||||
			return 2
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if t1 == 'r' && t2 == ')' {
 | 
			
		||||
			out.WriteString("®")
 | 
			
		||||
			return 2
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' {
 | 
			
		||||
			out.WriteString("™")
 | 
			
		||||
			return 3
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte(text[0])
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	if len(text) >= 2 {
 | 
			
		||||
		if text[1] == '-' {
 | 
			
		||||
			out.WriteString("—")
 | 
			
		||||
			return 1
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if wordBoundary(previousChar) && wordBoundary(text[1]) {
 | 
			
		||||
			out.WriteString("–")
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte(text[0])
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	if len(text) >= 3 && text[1] == '-' && text[2] == '-' {
 | 
			
		||||
		out.WriteString("—")
 | 
			
		||||
		return 2
 | 
			
		||||
	}
 | 
			
		||||
	if len(text) >= 2 && text[1] == '-' {
 | 
			
		||||
		out.WriteString("–")
 | 
			
		||||
		return 1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte(text[0])
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte, addNBSP bool) int {
 | 
			
		||||
	if bytes.HasPrefix(text, []byte(""")) {
 | 
			
		||||
		nextChar := byte(0)
 | 
			
		||||
		if len(text) >= 7 {
 | 
			
		||||
			nextChar = text[6]
 | 
			
		||||
		}
 | 
			
		||||
		if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, addNBSP) {
 | 
			
		||||
			return 5
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if bytes.HasPrefix(text, []byte("�")) {
 | 
			
		||||
		return 3
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte('&')
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartAmp(angledQuotes, addNBSP bool) func(*bytes.Buffer, byte, []byte) int {
 | 
			
		||||
	var quote byte = 'd'
 | 
			
		||||
	if angledQuotes {
 | 
			
		||||
		quote = 'a'
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return func(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
		return r.smartAmpVariant(out, previousChar, text, quote, addNBSP)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	if len(text) >= 3 && text[1] == '.' && text[2] == '.' {
 | 
			
		||||
		out.WriteString("…")
 | 
			
		||||
		return 2
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' {
 | 
			
		||||
		out.WriteString("…")
 | 
			
		||||
		return 4
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte(text[0])
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	if len(text) >= 2 && text[1] == '`' {
 | 
			
		||||
		nextChar := byte(0)
 | 
			
		||||
		if len(text) >= 3 {
 | 
			
		||||
			nextChar = text[2]
 | 
			
		||||
		}
 | 
			
		||||
		if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) {
 | 
			
		||||
			return 1
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte(text[0])
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
 | 
			
		||||
		// is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b
 | 
			
		||||
		// note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8)
 | 
			
		||||
		//       and avoid changing dates like 1/23/2005 into fractions.
 | 
			
		||||
		numEnd := 0
 | 
			
		||||
		for len(text) > numEnd && isdigit(text[numEnd]) {
 | 
			
		||||
			numEnd++
 | 
			
		||||
		}
 | 
			
		||||
		if numEnd == 0 {
 | 
			
		||||
			out.WriteByte(text[0])
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
		denStart := numEnd + 1
 | 
			
		||||
		if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 {
 | 
			
		||||
			denStart = numEnd + 3
 | 
			
		||||
		} else if len(text) < numEnd+2 || text[numEnd] != '/' {
 | 
			
		||||
			out.WriteByte(text[0])
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
		denEnd := denStart
 | 
			
		||||
		for len(text) > denEnd && isdigit(text[denEnd]) {
 | 
			
		||||
			denEnd++
 | 
			
		||||
		}
 | 
			
		||||
		if denEnd == denStart {
 | 
			
		||||
			out.WriteByte(text[0])
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
		if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' {
 | 
			
		||||
			out.WriteString("<sup>")
 | 
			
		||||
			out.Write(text[:numEnd])
 | 
			
		||||
			out.WriteString("</sup>⁄<sub>")
 | 
			
		||||
			out.Write(text[denStart:denEnd])
 | 
			
		||||
			out.WriteString("</sub>")
 | 
			
		||||
			return denEnd - 1
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte(text[0])
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
 | 
			
		||||
		if text[0] == '1' && text[1] == '/' && text[2] == '2' {
 | 
			
		||||
			if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' {
 | 
			
		||||
				out.WriteString("½")
 | 
			
		||||
				return 2
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if text[0] == '1' && text[1] == '/' && text[2] == '4' {
 | 
			
		||||
			if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') {
 | 
			
		||||
				out.WriteString("¼")
 | 
			
		||||
				return 2
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if text[0] == '3' && text[1] == '/' && text[2] == '4' {
 | 
			
		||||
			if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') {
 | 
			
		||||
				out.WriteString("¾")
 | 
			
		||||
				return 2
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.WriteByte(text[0])
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int {
 | 
			
		||||
	nextChar := byte(0)
 | 
			
		||||
	if len(text) > 1 {
 | 
			
		||||
		nextChar = text[1]
 | 
			
		||||
	}
 | 
			
		||||
	if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, false) {
 | 
			
		||||
		out.WriteString(""")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	return r.smartDoubleQuoteVariant(out, previousChar, text, 'd')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartAngledDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	return r.smartDoubleQuoteVariant(out, previousChar, text, 'a')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text []byte) int {
 | 
			
		||||
	i := 0
 | 
			
		||||
 | 
			
		||||
	for i < len(text) && text[i] != '>' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out.Write(text[:i+1])
 | 
			
		||||
	return i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int
 | 
			
		||||
 | 
			
		||||
// NewSmartypantsRenderer constructs a Smartypants renderer object.
 | 
			
		||||
func NewSmartypantsRenderer(flags Flags) *SPRenderer {
 | 
			
		||||
	var (
 | 
			
		||||
		r SPRenderer
 | 
			
		||||
 | 
			
		||||
		smartAmpAngled      = r.smartAmp(true, false)
 | 
			
		||||
		smartAmpAngledNBSP  = r.smartAmp(true, true)
 | 
			
		||||
		smartAmpRegular     = r.smartAmp(false, false)
 | 
			
		||||
		smartAmpRegularNBSP = r.smartAmp(false, true)
 | 
			
		||||
 | 
			
		||||
		addNBSP = flags&SmartypantsQuotesNBSP != 0
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if flags&SmartypantsAngledQuotes == 0 {
 | 
			
		||||
		r.callbacks['"'] = r.smartDoubleQuote
 | 
			
		||||
		if !addNBSP {
 | 
			
		||||
			r.callbacks['&'] = smartAmpRegular
 | 
			
		||||
		} else {
 | 
			
		||||
			r.callbacks['&'] = smartAmpRegularNBSP
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		r.callbacks['"'] = r.smartAngledDoubleQuote
 | 
			
		||||
		if !addNBSP {
 | 
			
		||||
			r.callbacks['&'] = smartAmpAngled
 | 
			
		||||
		} else {
 | 
			
		||||
			r.callbacks['&'] = smartAmpAngledNBSP
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	r.callbacks['\''] = r.smartSingleQuote
 | 
			
		||||
	r.callbacks['('] = r.smartParens
 | 
			
		||||
	if flags&SmartypantsDashes != 0 {
 | 
			
		||||
		if flags&SmartypantsLatexDashes == 0 {
 | 
			
		||||
			r.callbacks['-'] = r.smartDash
 | 
			
		||||
		} else {
 | 
			
		||||
			r.callbacks['-'] = r.smartDashLatex
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	r.callbacks['.'] = r.smartPeriod
 | 
			
		||||
	if flags&SmartypantsFractions == 0 {
 | 
			
		||||
		r.callbacks['1'] = r.smartNumber
 | 
			
		||||
		r.callbacks['3'] = r.smartNumber
 | 
			
		||||
	} else {
 | 
			
		||||
		for ch := '1'; ch <= '9'; ch++ {
 | 
			
		||||
			r.callbacks[ch] = r.smartNumberGeneric
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	r.callbacks['<'] = r.smartLeftAngle
 | 
			
		||||
	r.callbacks['`'] = r.smartBacktick
 | 
			
		||||
	return &r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Process is the entry point of the Smartypants renderer.
 | 
			
		||||
func (r *SPRenderer) Process(w io.Writer, text []byte) {
 | 
			
		||||
	mark := 0
 | 
			
		||||
	for i := 0; i < len(text); i++ {
 | 
			
		||||
		if action := r.callbacks[text[i]]; action != nil {
 | 
			
		||||
			if i > mark {
 | 
			
		||||
				w.Write(text[mark:i])
 | 
			
		||||
			}
 | 
			
		||||
			previousChar := byte(0)
 | 
			
		||||
			if i > 0 {
 | 
			
		||||
				previousChar = text[i-1]
 | 
			
		||||
			}
 | 
			
		||||
			var tmp bytes.Buffer
 | 
			
		||||
			i += action(&tmp, previousChar, text[i:])
 | 
			
		||||
			w.Write(tmp.Bytes())
 | 
			
		||||
			mark = i + 1
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if mark < len(text) {
 | 
			
		||||
		w.Write(text[mark:])
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								vendor/github.com/gomarkdown/markdown/markdown.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								vendor/github.com/gomarkdown/markdown/markdown.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
package markdown
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
	"github.com/gomarkdown/markdown/html"
 | 
			
		||||
	"github.com/gomarkdown/markdown/parser"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Renderer is an interface for implementing custom renderers.
 | 
			
		||||
type Renderer interface {
 | 
			
		||||
	// RenderNode renders markdown node to w.
 | 
			
		||||
	// It's called once for a leaf node.
 | 
			
		||||
	// It's called twice for non-leaf nodes:
 | 
			
		||||
	// * first with entering=true
 | 
			
		||||
	// * then with entering=false
 | 
			
		||||
	//
 | 
			
		||||
	// Return value is a way to tell the calling walker to adjust its walk
 | 
			
		||||
	// pattern: e.g. it can terminate the traversal by returning Terminate. Or it
 | 
			
		||||
	// can ask the walker to skip a subtree of this node by returning SkipChildren.
 | 
			
		||||
	// The typical behavior is to return GoToNext, which asks for the usual
 | 
			
		||||
	// traversal to the next node.
 | 
			
		||||
	RenderNode(w io.Writer, node ast.Node, entering bool) ast.WalkStatus
 | 
			
		||||
 | 
			
		||||
	// RenderHeader is a method that allows the renderer to produce some
 | 
			
		||||
	// content preceding the main body of the output document. The header is
 | 
			
		||||
	// understood in the broad sense here. For example, the default HTML
 | 
			
		||||
	// renderer will write not only the HTML document preamble, but also the
 | 
			
		||||
	// table of contents if it was requested.
 | 
			
		||||
	//
 | 
			
		||||
	// The method will be passed an entire document tree, in case a particular
 | 
			
		||||
	// implementation needs to inspect it to produce output.
 | 
			
		||||
	//
 | 
			
		||||
	// The output should be written to the supplied writer w. If your
 | 
			
		||||
	// implementation has no header to write, supply an empty implementation.
 | 
			
		||||
	RenderHeader(w io.Writer, ast ast.Node)
 | 
			
		||||
 | 
			
		||||
	// RenderFooter is a symmetric counterpart of RenderHeader.
 | 
			
		||||
	RenderFooter(w io.Writer, ast ast.Node)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse parsers a markdown document using provided parser. If parser is nil,
 | 
			
		||||
// we use parser configured with parser.CommonExtensions.
 | 
			
		||||
//
 | 
			
		||||
// It returns AST (abstract syntax tree) that can be converted to another
 | 
			
		||||
// format using Render function.
 | 
			
		||||
func Parse(markdown []byte, p *parser.Parser) ast.Node {
 | 
			
		||||
	if p == nil {
 | 
			
		||||
		p = parser.New()
 | 
			
		||||
	}
 | 
			
		||||
	return p.Parse(markdown)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Render uses renderer to convert parsed markdown document into a different format.
 | 
			
		||||
//
 | 
			
		||||
// To convert to HTML, pass html.Renderer
 | 
			
		||||
func Render(doc ast.Node, renderer Renderer) []byte {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	renderer.RenderHeader(&buf, doc)
 | 
			
		||||
	ast.WalkFunc(doc, func(node ast.Node, entering bool) ast.WalkStatus {
 | 
			
		||||
		return renderer.RenderNode(&buf, node, entering)
 | 
			
		||||
	})
 | 
			
		||||
	renderer.RenderFooter(&buf, doc)
 | 
			
		||||
	return buf.Bytes()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToHTML converts markdownDoc to HTML.
 | 
			
		||||
//
 | 
			
		||||
// You can optionally pass a parser and renderer. This allows to customize
 | 
			
		||||
// a parser, use a customized html render or use completely custom renderer.
 | 
			
		||||
//
 | 
			
		||||
// If you pass nil for both, we use parser configured with parser.CommonExtensions
 | 
			
		||||
// and html.Renderer configured with html.CommonFlags.
 | 
			
		||||
func ToHTML(markdown []byte, p *parser.Parser, renderer Renderer) []byte {
 | 
			
		||||
	doc := Parse(markdown, p)
 | 
			
		||||
	if renderer == nil {
 | 
			
		||||
		opts := html.RendererOptions{
 | 
			
		||||
			Flags: html.CommonFlags,
 | 
			
		||||
		}
 | 
			
		||||
		renderer = html.NewRenderer(opts)
 | 
			
		||||
	}
 | 
			
		||||
	return Render(doc, renderer)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								vendor/github.com/gomarkdown/markdown/parser/aside.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/gomarkdown/markdown/parser/aside.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// returns aisde prefix length
 | 
			
		||||
func (p *Parser) asidePrefix(data []byte) int {
 | 
			
		||||
	i := 0
 | 
			
		||||
	n := len(data)
 | 
			
		||||
	for i < 3 && i < n && data[i] == ' ' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	if i+1 < n && data[i] == 'A' && data[i+1] == '>' {
 | 
			
		||||
		if i+2 < n && data[i+2] == ' ' {
 | 
			
		||||
			return i + 3
 | 
			
		||||
		}
 | 
			
		||||
		return i + 2
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// aside ends with at least one blank line
 | 
			
		||||
// followed by something without a aside prefix
 | 
			
		||||
func (p *Parser) terminateAside(data []byte, beg, end int) bool {
 | 
			
		||||
	if p.isEmpty(data[beg:]) <= 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if end >= len(data) {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return p.asidePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parse a aside fragment
 | 
			
		||||
func (p *Parser) aside(data []byte) int {
 | 
			
		||||
	var raw bytes.Buffer
 | 
			
		||||
	beg, end := 0, 0
 | 
			
		||||
	// identical to quote
 | 
			
		||||
	for beg < len(data) {
 | 
			
		||||
		end = beg
 | 
			
		||||
		// Step over whole lines, collecting them. While doing that, check for
 | 
			
		||||
		// fenced code and if one's found, incorporate it altogether,
 | 
			
		||||
		// irregardless of any contents inside it
 | 
			
		||||
		for end < len(data) && data[end] != '\n' {
 | 
			
		||||
			if p.extensions&FencedCode != 0 {
 | 
			
		||||
				if i := p.fencedCodeBlock(data[end:], false); i > 0 {
 | 
			
		||||
					// -1 to compensate for the extra end++ after the loop:
 | 
			
		||||
					end += i - 1
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			end++
 | 
			
		||||
		}
 | 
			
		||||
		end = skipCharN(data, end, '\n', 1)
 | 
			
		||||
		if pre := p.asidePrefix(data[beg:]); pre > 0 {
 | 
			
		||||
			// skip the prefix
 | 
			
		||||
			beg += pre
 | 
			
		||||
		} else if p.terminateAside(data, beg, end) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		// this line is part of the aside
 | 
			
		||||
		raw.Write(data[beg:end])
 | 
			
		||||
		beg = end
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block := p.addBlock(&ast.Aside{})
 | 
			
		||||
	p.block(raw.Bytes())
 | 
			
		||||
	p.finalize(block)
 | 
			
		||||
	return end
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								vendor/github.com/gomarkdown/markdown/parser/attribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								vendor/github.com/gomarkdown/markdown/parser/attribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// attribute parses a (potential) block attribute and adds it to p.
 | 
			
		||||
func (p *Parser) attribute(data []byte) []byte {
 | 
			
		||||
	if len(data) < 3 {
 | 
			
		||||
		return data
 | 
			
		||||
	}
 | 
			
		||||
	i := 0
 | 
			
		||||
	if data[i] != '{' {
 | 
			
		||||
		return data
 | 
			
		||||
	}
 | 
			
		||||
	i++
 | 
			
		||||
 | 
			
		||||
	// last character must be a } otherwise it's not an attribute
 | 
			
		||||
	end := skipUntilChar(data, i, '\n')
 | 
			
		||||
	if data[end-1] != '}' {
 | 
			
		||||
		return data
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i = skipSpace(data, i)
 | 
			
		||||
	b := &ast.Attribute{Attrs: make(map[string][]byte)}
 | 
			
		||||
 | 
			
		||||
	esc := false
 | 
			
		||||
	quote := false
 | 
			
		||||
	trail := 0
 | 
			
		||||
Loop:
 | 
			
		||||
	for ; i < len(data); i++ {
 | 
			
		||||
		switch data[i] {
 | 
			
		||||
		case ' ', '\t', '\f', '\v':
 | 
			
		||||
			if quote {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			chunk := data[trail+1 : i]
 | 
			
		||||
			if len(chunk) == 0 {
 | 
			
		||||
				trail = i
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			switch {
 | 
			
		||||
			case chunk[0] == '.':
 | 
			
		||||
				b.Classes = append(b.Classes, chunk[1:])
 | 
			
		||||
			case chunk[0] == '#':
 | 
			
		||||
				b.ID = chunk[1:]
 | 
			
		||||
			default:
 | 
			
		||||
				k, v := keyValue(chunk)
 | 
			
		||||
				if k != nil && v != nil {
 | 
			
		||||
					b.Attrs[string(k)] = v
 | 
			
		||||
				} else {
 | 
			
		||||
					// this is illegal in an attribute
 | 
			
		||||
					return data
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			trail = i
 | 
			
		||||
		case '"':
 | 
			
		||||
			if esc {
 | 
			
		||||
				esc = !esc
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			quote = !quote
 | 
			
		||||
		case '\\':
 | 
			
		||||
			esc = !esc
 | 
			
		||||
		case '}':
 | 
			
		||||
			if esc {
 | 
			
		||||
				esc = !esc
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			chunk := data[trail+1 : i]
 | 
			
		||||
			if len(chunk) == 0 {
 | 
			
		||||
				return data
 | 
			
		||||
			}
 | 
			
		||||
			switch {
 | 
			
		||||
			case chunk[0] == '.':
 | 
			
		||||
				b.Classes = append(b.Classes, chunk[1:])
 | 
			
		||||
			case chunk[0] == '#':
 | 
			
		||||
				b.ID = chunk[1:]
 | 
			
		||||
			default:
 | 
			
		||||
				k, v := keyValue(chunk)
 | 
			
		||||
				if k != nil && v != nil {
 | 
			
		||||
					b.Attrs[string(k)] = v
 | 
			
		||||
				} else {
 | 
			
		||||
					return data
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			i++
 | 
			
		||||
			break Loop
 | 
			
		||||
		default:
 | 
			
		||||
			esc = false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p.attr = b
 | 
			
		||||
	return data[i:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// key="value" quotes are mandatory.
 | 
			
		||||
func keyValue(data []byte) ([]byte, []byte) {
 | 
			
		||||
	chunk := bytes.SplitN(data, []byte{'='}, 2)
 | 
			
		||||
	if len(chunk) != 2 {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	key := chunk[0]
 | 
			
		||||
	value := chunk[1]
 | 
			
		||||
 | 
			
		||||
	if len(value) < 3 || len(key) == 0 {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	if value[0] != '"' || value[len(value)-1] != '"' {
 | 
			
		||||
		return key, nil
 | 
			
		||||
	}
 | 
			
		||||
	return key, value[1 : len(value)-1]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1978
									
								
								vendor/github.com/gomarkdown/markdown/parser/block.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1978
									
								
								vendor/github.com/gomarkdown/markdown/parser/block.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										29
									
								
								vendor/github.com/gomarkdown/markdown/parser/callout.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/gomarkdown/markdown/parser/callout.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// IsCallout detects a callout in the following format: <<N>> Where N is a integer > 0.
 | 
			
		||||
func IsCallout(data []byte) (id []byte, consumed int) {
 | 
			
		||||
	if !bytes.HasPrefix(data, []byte("<<")) {
 | 
			
		||||
		return nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	start := 2
 | 
			
		||||
	end := bytes.Index(data[start:], []byte(">>"))
 | 
			
		||||
	if end < 0 {
 | 
			
		||||
		return nil, 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b := data[start : start+end]
 | 
			
		||||
	b = bytes.TrimSpace(b)
 | 
			
		||||
	i, err := strconv.Atoi(string(b))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	if i <= 0 {
 | 
			
		||||
		return nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	return b, start + end + 2 // 2 for >>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								vendor/github.com/gomarkdown/markdown/parser/caption.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								vendor/github.com/gomarkdown/markdown/parser/caption.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// caption checks for a caption, it returns the caption data and a potential "headingID".
 | 
			
		||||
func (p *Parser) caption(data, caption []byte) ([]byte, string, int) {
 | 
			
		||||
	if !bytes.HasPrefix(data, caption) {
 | 
			
		||||
		return nil, "", 0
 | 
			
		||||
	}
 | 
			
		||||
	j := len(caption)
 | 
			
		||||
	data = data[j:]
 | 
			
		||||
	end := p.linesUntilEmpty(data)
 | 
			
		||||
 | 
			
		||||
	data = data[:end]
 | 
			
		||||
 | 
			
		||||
	id, start := captionID(data)
 | 
			
		||||
	if id != "" {
 | 
			
		||||
		return data[:start], id, end + j
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return data, "", end + j
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// linesUntilEmpty scans lines up to the first empty line.
 | 
			
		||||
func (p *Parser) linesUntilEmpty(data []byte) int {
 | 
			
		||||
	line, i := 0, 0
 | 
			
		||||
 | 
			
		||||
	for line < len(data) {
 | 
			
		||||
		i++
 | 
			
		||||
 | 
			
		||||
		// find the end of this line
 | 
			
		||||
		for i < len(data) && data[i-1] != '\n' {
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if p.isEmpty(data[line:i]) == 0 {
 | 
			
		||||
			line = i
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
	return i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// captionID checks if the caption *ends* in {#....}. If so the text after {# is taken to be
 | 
			
		||||
// the ID/anchor of the entire figure block.
 | 
			
		||||
func captionID(data []byte) (string, int) {
 | 
			
		||||
	end := len(data)
 | 
			
		||||
 | 
			
		||||
	j, k := 0, 0
 | 
			
		||||
	// find start/end of heading id
 | 
			
		||||
	for j = 0; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ {
 | 
			
		||||
	}
 | 
			
		||||
	for k = j + 1; k < end && data[k] != '}'; k++ {
 | 
			
		||||
	}
 | 
			
		||||
	// remains must be whitespace.
 | 
			
		||||
	for l := k + 1; l < end; l++ {
 | 
			
		||||
		if !isSpace(data[l]) {
 | 
			
		||||
			return "", 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if j > 0 && k > 0 && j+2 < k {
 | 
			
		||||
		return string(data[j+2 : k]), j
 | 
			
		||||
	}
 | 
			
		||||
	return "", 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								vendor/github.com/gomarkdown/markdown/parser/citation.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/gomarkdown/markdown/parser/citation.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// citation parses a citation. In its most simple form [@ref], we allow multiple
 | 
			
		||||
// being separated by semicolons and a sub reference inside ala pandoc: [@ref, p. 23].
 | 
			
		||||
// Each citation can have a modifier: !, ? or - wich mean:
 | 
			
		||||
//
 | 
			
		||||
// ! - normative
 | 
			
		||||
// ? - formative
 | 
			
		||||
// - - suppressed
 | 
			
		||||
//
 | 
			
		||||
// The suffix starts after a comma, we strip any whitespace before and after. If the output
 | 
			
		||||
// allows for it, this can be rendered.
 | 
			
		||||
func citation(p *Parser, data []byte, offset int) (int, ast.Node) {
 | 
			
		||||
	// look for the matching closing bracket
 | 
			
		||||
	i := offset + 1
 | 
			
		||||
	for level := 1; level > 0 && i < len(data); i++ {
 | 
			
		||||
		switch {
 | 
			
		||||
		case data[i] == '\n':
 | 
			
		||||
			// no newlines allowed.
 | 
			
		||||
			return 0, nil
 | 
			
		||||
 | 
			
		||||
		case data[i-1] == '\\':
 | 
			
		||||
			continue
 | 
			
		||||
 | 
			
		||||
		case data[i] == '[':
 | 
			
		||||
			level++
 | 
			
		||||
 | 
			
		||||
		case data[i] == ']':
 | 
			
		||||
			level--
 | 
			
		||||
			if level <= 0 {
 | 
			
		||||
				i-- // compensate for extra i++ in for loop
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if i >= len(data) {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	node := &ast.Citation{}
 | 
			
		||||
 | 
			
		||||
	citations := bytes.Split(data[1:i], []byte(";"))
 | 
			
		||||
	for _, citation := range citations {
 | 
			
		||||
		var suffix []byte
 | 
			
		||||
		citation = bytes.TrimSpace(citation)
 | 
			
		||||
		j := 0
 | 
			
		||||
		if citation[j] != '@' {
 | 
			
		||||
			// not a citation, drop out entirely.
 | 
			
		||||
			return 0, nil
 | 
			
		||||
		}
 | 
			
		||||
		if c := bytes.Index(citation, []byte(",")); c > 0 {
 | 
			
		||||
			part := citation[:c]
 | 
			
		||||
			suff := citation[c+1:]
 | 
			
		||||
			part = bytes.TrimSpace(part)
 | 
			
		||||
			suff = bytes.TrimSpace(suff)
 | 
			
		||||
 | 
			
		||||
			citation = part
 | 
			
		||||
			suffix = suff
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		citeType := ast.CitationTypeInformative
 | 
			
		||||
		j = 1
 | 
			
		||||
		switch citation[j] {
 | 
			
		||||
		case '!':
 | 
			
		||||
			citeType = ast.CitationTypeNormative
 | 
			
		||||
			j++
 | 
			
		||||
		case '?':
 | 
			
		||||
			citeType = ast.CitationTypeInformative
 | 
			
		||||
			j++
 | 
			
		||||
		case '-':
 | 
			
		||||
			citeType = ast.CitationTypeSuppressed
 | 
			
		||||
			j++
 | 
			
		||||
		}
 | 
			
		||||
		node.Destination = append(node.Destination, citation[j:])
 | 
			
		||||
		node.Type = append(node.Type, citeType)
 | 
			
		||||
		node.Suffix = append(node.Suffix, suffix)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return i + 1, node
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/gomarkdown/markdown/parser/esc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/gomarkdown/markdown/parser/esc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
// isEscape returns true if byte i is prefixed by an odd number of backslahses.
 | 
			
		||||
func isEscape(data []byte, i int) bool {
 | 
			
		||||
	if i == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if i == 1 {
 | 
			
		||||
		return data[0] == '\\'
 | 
			
		||||
	}
 | 
			
		||||
	j := i - 1
 | 
			
		||||
	for ; j >= 0; j-- {
 | 
			
		||||
		if data[j] != '\\' {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	j++
 | 
			
		||||
	// odd number of backslahes means escape
 | 
			
		||||
	return (i-j)%2 != 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								vendor/github.com/gomarkdown/markdown/parser/figures.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								vendor/github.com/gomarkdown/markdown/parser/figures.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// sFigureLine checks if there's a figure line (e.g., !--- ) at the beginning of data,
 | 
			
		||||
// and returns the end index if so, or 0 otherwise.
 | 
			
		||||
func sFigureLine(data []byte, oldmarker string) (end int, marker string) {
 | 
			
		||||
	i, size := 0, 0
 | 
			
		||||
 | 
			
		||||
	n := len(data)
 | 
			
		||||
	// skip up to three spaces
 | 
			
		||||
	for i < n && i < 3 && data[i] == ' ' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// check for the marker characters: !
 | 
			
		||||
	if i+1 >= n {
 | 
			
		||||
		return 0, ""
 | 
			
		||||
	}
 | 
			
		||||
	if data[i] != '!' || data[i+1] != '-' {
 | 
			
		||||
		return 0, ""
 | 
			
		||||
	}
 | 
			
		||||
	i++
 | 
			
		||||
 | 
			
		||||
	c := data[i] // i.e. the -
 | 
			
		||||
 | 
			
		||||
	// the whole line must be the same char or whitespace
 | 
			
		||||
	for i < n && data[i] == c {
 | 
			
		||||
		size++
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// the marker char must occur at least 3 times
 | 
			
		||||
	if size < 3 {
 | 
			
		||||
		return 0, ""
 | 
			
		||||
	}
 | 
			
		||||
	marker = string(data[i-size : i])
 | 
			
		||||
 | 
			
		||||
	// if this is the end marker, it must match the beginning marker
 | 
			
		||||
	if oldmarker != "" && marker != oldmarker {
 | 
			
		||||
		return 0, ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// there is no syntax modifier although it might be an idea to re-use this space for something?
 | 
			
		||||
 | 
			
		||||
	i = skipChar(data, i, ' ')
 | 
			
		||||
	if i >= n || data[i] != '\n' {
 | 
			
		||||
		if i == n {
 | 
			
		||||
			return i, marker
 | 
			
		||||
		}
 | 
			
		||||
		return 0, ""
 | 
			
		||||
	}
 | 
			
		||||
	return i + 1, marker // Take newline into account.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// figureBlock returns the end index if data contains a figure block at the beginning,
 | 
			
		||||
// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects.
 | 
			
		||||
// If doRender is true, a final newline is mandatory to recognize the figure block.
 | 
			
		||||
func (p *Parser) figureBlock(data []byte, doRender bool) int {
 | 
			
		||||
	beg, marker := sFigureLine(data, "")
 | 
			
		||||
	if beg == 0 || beg >= len(data) {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var raw bytes.Buffer
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		// safe to assume beg < len(data)
 | 
			
		||||
 | 
			
		||||
		// check for the end of the code block
 | 
			
		||||
		figEnd, _ := sFigureLine(data[beg:], marker)
 | 
			
		||||
		if figEnd != 0 {
 | 
			
		||||
			beg += figEnd
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// copy the current line
 | 
			
		||||
		end := skipUntilChar(data, beg, '\n') + 1
 | 
			
		||||
 | 
			
		||||
		// did we reach the end of the buffer without a closing marker?
 | 
			
		||||
		if end >= len(data) {
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// verbatim copy to the working buffer
 | 
			
		||||
		if doRender {
 | 
			
		||||
			raw.Write(data[beg:end])
 | 
			
		||||
		}
 | 
			
		||||
		beg = end
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !doRender {
 | 
			
		||||
		return beg
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	figure := &ast.CaptionFigure{}
 | 
			
		||||
	p.addBlock(figure)
 | 
			
		||||
	p.block(raw.Bytes())
 | 
			
		||||
 | 
			
		||||
	defer p.finalize(figure)
 | 
			
		||||
 | 
			
		||||
	if captionContent, id, consumed := p.caption(data[beg:], []byte("Figure: ")); consumed > 0 {
 | 
			
		||||
		caption := &ast.Caption{}
 | 
			
		||||
		p.Inline(caption, captionContent)
 | 
			
		||||
 | 
			
		||||
		figure.HeadingID = id
 | 
			
		||||
 | 
			
		||||
		p.addChild(caption)
 | 
			
		||||
 | 
			
		||||
		beg += consumed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p.finalize(figure)
 | 
			
		||||
	return beg
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										129
									
								
								vendor/github.com/gomarkdown/markdown/parser/include.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								vendor/github.com/gomarkdown/markdown/parser/include.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// isInclude parses {{...}}[...], that contains a path between the {{, the [...] syntax contains
 | 
			
		||||
// an address to select which lines to include. It is treated as an opaque string and just given
 | 
			
		||||
// to readInclude.
 | 
			
		||||
func (p *Parser) isInclude(data []byte) (filename string, address []byte, consumed int) {
 | 
			
		||||
	i := skipCharN(data, 0, ' ', 3) // start with up to 3 spaces
 | 
			
		||||
	if len(data[i:]) < 3 {
 | 
			
		||||
		return "", nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	if data[i] != '{' || data[i+1] != '{' {
 | 
			
		||||
		return "", nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	start := i + 2
 | 
			
		||||
 | 
			
		||||
	// find the end delimiter
 | 
			
		||||
	i = skipUntilChar(data, i, '}')
 | 
			
		||||
	if i+1 >= len(data) {
 | 
			
		||||
		return "", nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	end := i
 | 
			
		||||
	i++
 | 
			
		||||
	if data[i] != '}' {
 | 
			
		||||
		return "", nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	filename = string(data[start:end])
 | 
			
		||||
 | 
			
		||||
	if i+1 < len(data) && data[i+1] == '[' { // potential address specification
 | 
			
		||||
		start := i + 2
 | 
			
		||||
 | 
			
		||||
		end = skipUntilChar(data, start, ']')
 | 
			
		||||
		if end >= len(data) {
 | 
			
		||||
			return "", nil, 0
 | 
			
		||||
		}
 | 
			
		||||
		address = data[start:end]
 | 
			
		||||
		return filename, address, end + 1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return filename, address, i + 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) readInclude(from, file string, address []byte) []byte {
 | 
			
		||||
	if p.Opts.ReadIncludeFn != nil {
 | 
			
		||||
		return p.Opts.ReadIncludeFn(from, file, address)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isCodeInclude parses <{{...}} which is similar to isInclude the returned bytes are, however wrapped in a code block.
 | 
			
		||||
func (p *Parser) isCodeInclude(data []byte) (filename string, address []byte, consumed int) {
 | 
			
		||||
	i := skipCharN(data, 0, ' ', 3) // start with up to 3 spaces
 | 
			
		||||
	if len(data[i:]) < 3 {
 | 
			
		||||
		return "", nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	if data[i] != '<' {
 | 
			
		||||
		return "", nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	start := i
 | 
			
		||||
 | 
			
		||||
	filename, address, consumed = p.isInclude(data[i+1:])
 | 
			
		||||
	if consumed == 0 {
 | 
			
		||||
		return "", nil, 0
 | 
			
		||||
	}
 | 
			
		||||
	return filename, address, start + consumed + 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// readCodeInclude acts like include except the returned bytes are wrapped in a fenced code block.
 | 
			
		||||
func (p *Parser) readCodeInclude(from, file string, address []byte) []byte {
 | 
			
		||||
	data := p.readInclude(from, file, address)
 | 
			
		||||
	if data == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	ext := path.Ext(file)
 | 
			
		||||
	buf := &bytes.Buffer{}
 | 
			
		||||
	buf.Write([]byte("```"))
 | 
			
		||||
	if ext != "" { // starts with a dot
 | 
			
		||||
		buf.WriteString(" " + ext[1:] + "\n")
 | 
			
		||||
	} else {
 | 
			
		||||
		buf.WriteByte('\n')
 | 
			
		||||
	}
 | 
			
		||||
	buf.Write(data)
 | 
			
		||||
	buf.WriteString("```\n")
 | 
			
		||||
	return buf.Bytes()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// incStack hold the current stack of chained includes. Each value is the containing
 | 
			
		||||
// path of the file being parsed.
 | 
			
		||||
type incStack struct {
 | 
			
		||||
	stack []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newIncStack() *incStack {
 | 
			
		||||
	return &incStack{stack: []string{}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Push updates i with new.
 | 
			
		||||
func (i *incStack) Push(new string) {
 | 
			
		||||
	if path.IsAbs(new) {
 | 
			
		||||
		i.stack = append(i.stack, path.Dir(new))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	last := ""
 | 
			
		||||
	if len(i.stack) > 0 {
 | 
			
		||||
		last = i.stack[len(i.stack)-1]
 | 
			
		||||
	}
 | 
			
		||||
	i.stack = append(i.stack, path.Dir(filepath.Join(last, new)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Pop pops the last value.
 | 
			
		||||
func (i *incStack) Pop() {
 | 
			
		||||
	if len(i.stack) == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	i.stack = i.stack[:len(i.stack)-1]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *incStack) Last() string {
 | 
			
		||||
	if len(i.stack) == 0 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return i.stack[len(i.stack)-1]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1284
									
								
								vendor/github.com/gomarkdown/markdown/parser/inline.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1284
									
								
								vendor/github.com/gomarkdown/markdown/parser/inline.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										36
									
								
								vendor/github.com/gomarkdown/markdown/parser/matter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								vendor/github.com/gomarkdown/markdown/parser/matter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (p *Parser) documentMatter(data []byte) int {
 | 
			
		||||
	if data[0] != '{' {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	consumed := 0
 | 
			
		||||
	matter := ast.DocumentMatterNone
 | 
			
		||||
	if bytes.HasPrefix(data, []byte("{frontmatter}")) {
 | 
			
		||||
		consumed = len("{frontmatter}")
 | 
			
		||||
		matter = ast.DocumentMatterFront
 | 
			
		||||
	}
 | 
			
		||||
	if bytes.HasPrefix(data, []byte("{mainmatter}")) {
 | 
			
		||||
		consumed = len("{mainmatter}")
 | 
			
		||||
		matter = ast.DocumentMatterMain
 | 
			
		||||
	}
 | 
			
		||||
	if bytes.HasPrefix(data, []byte("{backmatter}")) {
 | 
			
		||||
		consumed = len("{backmatter}")
 | 
			
		||||
		matter = ast.DocumentMatterBack
 | 
			
		||||
	}
 | 
			
		||||
	if consumed == 0 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	node := &ast.DocumentMatter{Matter: matter}
 | 
			
		||||
	p.addBlock(node)
 | 
			
		||||
	p.finalize(node)
 | 
			
		||||
 | 
			
		||||
	return consumed
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								vendor/github.com/gomarkdown/markdown/parser/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/gomarkdown/markdown/parser/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Flags control optional behavior of parser.
 | 
			
		||||
type Flags int
 | 
			
		||||
 | 
			
		||||
// Options is a collection of supplementary parameters tweaking the behavior of various parts of the parser.
 | 
			
		||||
type Options struct {
 | 
			
		||||
	ParserHook    BlockFunc
 | 
			
		||||
	ReadIncludeFn ReadIncludeFunc
 | 
			
		||||
 | 
			
		||||
	Flags Flags // Flags allow customizing parser's behavior
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parser renderer configuration options.
 | 
			
		||||
const (
 | 
			
		||||
	FlagsNone        Flags = 0
 | 
			
		||||
	SkipFootnoteList Flags = 1 << iota // Skip adding the footnote list (regardless if they are parsed)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// BlockFunc allows to registration of a parser function. If successful it
 | 
			
		||||
// returns an ast.Node, a buffer that should be parsed as a block and the the number of bytes consumed.
 | 
			
		||||
type BlockFunc func(data []byte) (ast.Node, []byte, int)
 | 
			
		||||
 | 
			
		||||
// ReadIncludeFunc should read the file under path and returns the read bytes,
 | 
			
		||||
// from will be set to the name of the current file being parsed. Initially
 | 
			
		||||
// this will be empty. address is the optional address specifier of which lines
 | 
			
		||||
// of the file to return. If this function is not set no data will be read.
 | 
			
		||||
type ReadIncludeFunc func(from, path string, address []byte) []byte
 | 
			
		||||
							
								
								
									
										812
									
								
								vendor/github.com/gomarkdown/markdown/parser/parser.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										812
									
								
								vendor/github.com/gomarkdown/markdown/parser/parser.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,812 @@
 | 
			
		||||
/*
 | 
			
		||||
Package parser implements parser for markdown text that generates AST (abstract syntax tree).
 | 
			
		||||
*/
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Extensions is a bitmask of enabled parser extensions.
 | 
			
		||||
type Extensions int
 | 
			
		||||
 | 
			
		||||
// Bit flags representing markdown parsing extensions.
 | 
			
		||||
// Use | (or) to specify multiple extensions.
 | 
			
		||||
const (
 | 
			
		||||
	NoExtensions           Extensions = 0
 | 
			
		||||
	NoIntraEmphasis        Extensions = 1 << iota // Ignore emphasis markers inside words
 | 
			
		||||
	Tables                                        // Parse tables
 | 
			
		||||
	FencedCode                                    // Parse fenced code blocks
 | 
			
		||||
	Autolink                                      // Detect embedded URLs that are not explicitly marked
 | 
			
		||||
	Strikethrough                                 // Strikethrough text using ~~test~~
 | 
			
		||||
	LaxHTMLBlocks                                 // Loosen up HTML block parsing rules
 | 
			
		||||
	SpaceHeadings                                 // Be strict about prefix heading rules
 | 
			
		||||
	HardLineBreak                                 // Translate newlines into line breaks
 | 
			
		||||
	NonBlockingSpace                              // Translate backspace spaces into line non-blocking spaces
 | 
			
		||||
	TabSizeEight                                  // Expand tabs to eight spaces instead of four
 | 
			
		||||
	Footnotes                                     // Pandoc-style footnotes
 | 
			
		||||
	NoEmptyLineBeforeBlock                        // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block
 | 
			
		||||
	HeadingIDs                                    // specify heading IDs  with {#id}
 | 
			
		||||
	Titleblock                                    // Titleblock ala pandoc
 | 
			
		||||
	AutoHeadingIDs                                // Create the heading ID from the text
 | 
			
		||||
	BackslashLineBreak                            // Translate trailing backslashes into line breaks
 | 
			
		||||
	DefinitionLists                               // Parse definition lists
 | 
			
		||||
	MathJax                                       // Parse MathJax
 | 
			
		||||
	OrderedListStart                              // Keep track of the first number used when starting an ordered list.
 | 
			
		||||
	Attributes                                    // Block Attributes
 | 
			
		||||
	SuperSubscript                                // Super- and subscript support: 2^10^, H~2~O.
 | 
			
		||||
	EmptyLinesBreakList                           // 2 empty lines break out of list
 | 
			
		||||
	Includes                                      // Support including other files.
 | 
			
		||||
	Mmark                                         // Support Mmark syntax, see https://mmark.nl/syntax
 | 
			
		||||
 | 
			
		||||
	CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode |
 | 
			
		||||
		Autolink | Strikethrough | SpaceHeadings | HeadingIDs |
 | 
			
		||||
		BackslashLineBreak | DefinitionLists | MathJax
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The size of a tab stop.
 | 
			
		||||
const (
 | 
			
		||||
	tabSizeDefault = 4
 | 
			
		||||
	tabSizeDouble  = 8
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// for each character that triggers a response when parsing inline data.
 | 
			
		||||
type inlineParser func(p *Parser, data []byte, offset int) (int, ast.Node)
 | 
			
		||||
 | 
			
		||||
// ReferenceOverrideFunc is expected to be called with a reference string and
 | 
			
		||||
// return either a valid Reference type that the reference string maps to or
 | 
			
		||||
// nil. If overridden is false, the default reference logic will be executed.
 | 
			
		||||
// See the documentation in Options for more details on use-case.
 | 
			
		||||
type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool)
 | 
			
		||||
 | 
			
		||||
// Parser is a type that holds extensions and the runtime state used by
 | 
			
		||||
// Parse, and the renderer. You can not use it directly, construct it with New.
 | 
			
		||||
type Parser struct {
 | 
			
		||||
 | 
			
		||||
	// ReferenceOverride is an optional function callback that is called every
 | 
			
		||||
	// time a reference is resolved. It can be set before starting parsing.
 | 
			
		||||
	//
 | 
			
		||||
	// In Markdown, the link reference syntax can be made to resolve a link to
 | 
			
		||||
	// a reference instead of an inline URL, in one of the following ways:
 | 
			
		||||
	//
 | 
			
		||||
	//  * [link text][refid]
 | 
			
		||||
	//  * [refid][]
 | 
			
		||||
	//
 | 
			
		||||
	// Usually, the refid is defined at the bottom of the Markdown document. If
 | 
			
		||||
	// this override function is provided, the refid is passed to the override
 | 
			
		||||
	// function first, before consulting the defined refids at the bottom. If
 | 
			
		||||
	// the override function indicates an override did not occur, the refids at
 | 
			
		||||
	// the bottom will be used to fill in the link details.
 | 
			
		||||
	ReferenceOverride ReferenceOverrideFunc
 | 
			
		||||
 | 
			
		||||
	Opts Options
 | 
			
		||||
 | 
			
		||||
	// after parsing, this is AST root of parsed markdown text
 | 
			
		||||
	Doc ast.Node
 | 
			
		||||
 | 
			
		||||
	extensions Extensions
 | 
			
		||||
 | 
			
		||||
	refs           map[string]*reference
 | 
			
		||||
	refsRecord     map[string]struct{}
 | 
			
		||||
	inlineCallback [256]inlineParser
 | 
			
		||||
	nesting        int
 | 
			
		||||
	maxNesting     int
 | 
			
		||||
	insideLink     bool
 | 
			
		||||
	indexCnt       int // incremented after every index
 | 
			
		||||
 | 
			
		||||
	// Footnotes need to be ordered as well as available to quickly check for
 | 
			
		||||
	// presence. If a ref is also a footnote, it's stored both in refs and here
 | 
			
		||||
	// in notes. Slice is nil if footnotes not enabled.
 | 
			
		||||
	notes []*reference
 | 
			
		||||
 | 
			
		||||
	tip                  ast.Node // = doc
 | 
			
		||||
	oldTip               ast.Node
 | 
			
		||||
	lastMatchedContainer ast.Node // = doc
 | 
			
		||||
	allClosed            bool
 | 
			
		||||
 | 
			
		||||
	// Attributes are attached to block level elements.
 | 
			
		||||
	attr *ast.Attribute
 | 
			
		||||
 | 
			
		||||
	includeStack *incStack
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a markdown parser with CommonExtensions.
 | 
			
		||||
//
 | 
			
		||||
// You can then call `doc := p.Parse(markdown)` to parse markdown document
 | 
			
		||||
// and `markdown.Render(doc, renderer)` to convert it to another format with
 | 
			
		||||
// a renderer.
 | 
			
		||||
func New() *Parser {
 | 
			
		||||
	return NewWithExtensions(CommonExtensions)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewWithExtensions creates a markdown parser with given extensions.
 | 
			
		||||
func NewWithExtensions(extension Extensions) *Parser {
 | 
			
		||||
	p := Parser{
 | 
			
		||||
		refs:         make(map[string]*reference),
 | 
			
		||||
		refsRecord:   make(map[string]struct{}),
 | 
			
		||||
		maxNesting:   16,
 | 
			
		||||
		insideLink:   false,
 | 
			
		||||
		Doc:          &ast.Document{},
 | 
			
		||||
		extensions:   extension,
 | 
			
		||||
		allClosed:    true,
 | 
			
		||||
		includeStack: newIncStack(),
 | 
			
		||||
	}
 | 
			
		||||
	p.tip = p.Doc
 | 
			
		||||
	p.oldTip = p.Doc
 | 
			
		||||
	p.lastMatchedContainer = p.Doc
 | 
			
		||||
 | 
			
		||||
	p.inlineCallback[' '] = maybeLineBreak
 | 
			
		||||
	p.inlineCallback['*'] = emphasis
 | 
			
		||||
	p.inlineCallback['_'] = emphasis
 | 
			
		||||
	if p.extensions&Strikethrough != 0 {
 | 
			
		||||
		p.inlineCallback['~'] = emphasis
 | 
			
		||||
	}
 | 
			
		||||
	p.inlineCallback['`'] = codeSpan
 | 
			
		||||
	p.inlineCallback['\n'] = lineBreak
 | 
			
		||||
	p.inlineCallback['['] = link
 | 
			
		||||
	p.inlineCallback['<'] = leftAngle
 | 
			
		||||
	p.inlineCallback['\\'] = escape
 | 
			
		||||
	p.inlineCallback['&'] = entity
 | 
			
		||||
	p.inlineCallback['!'] = maybeImage
 | 
			
		||||
	if p.extensions&Mmark != 0 {
 | 
			
		||||
		p.inlineCallback['('] = maybeShortRefOrIndex
 | 
			
		||||
	}
 | 
			
		||||
	p.inlineCallback['^'] = maybeInlineFootnoteOrSuper
 | 
			
		||||
	if p.extensions&Autolink != 0 {
 | 
			
		||||
		p.inlineCallback['h'] = maybeAutoLink
 | 
			
		||||
		p.inlineCallback['m'] = maybeAutoLink
 | 
			
		||||
		p.inlineCallback['f'] = maybeAutoLink
 | 
			
		||||
		p.inlineCallback['H'] = maybeAutoLink
 | 
			
		||||
		p.inlineCallback['M'] = maybeAutoLink
 | 
			
		||||
		p.inlineCallback['F'] = maybeAutoLink
 | 
			
		||||
	}
 | 
			
		||||
	if p.extensions&MathJax != 0 {
 | 
			
		||||
		p.inlineCallback['$'] = math
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) getRef(refid string) (ref *reference, found bool) {
 | 
			
		||||
	if p.ReferenceOverride != nil {
 | 
			
		||||
		r, overridden := p.ReferenceOverride(refid)
 | 
			
		||||
		if overridden {
 | 
			
		||||
			if r == nil {
 | 
			
		||||
				return nil, false
 | 
			
		||||
			}
 | 
			
		||||
			return &reference{
 | 
			
		||||
				link:     []byte(r.Link),
 | 
			
		||||
				title:    []byte(r.Title),
 | 
			
		||||
				noteID:   0,
 | 
			
		||||
				hasBlock: false,
 | 
			
		||||
				text:     []byte(r.Text)}, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// refs are case insensitive
 | 
			
		||||
	ref, found = p.refs[strings.ToLower(refid)]
 | 
			
		||||
	return ref, found
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) isFootnote(ref *reference) bool {
 | 
			
		||||
	_, ok := p.refsRecord[string(ref.link)]
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) finalize(block ast.Node) {
 | 
			
		||||
	p.tip = block.GetParent()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) addChild(node ast.Node) ast.Node {
 | 
			
		||||
	for !canNodeContain(p.tip, node) {
 | 
			
		||||
		p.finalize(p.tip)
 | 
			
		||||
	}
 | 
			
		||||
	ast.AppendChild(p.tip, node)
 | 
			
		||||
	p.tip = node
 | 
			
		||||
	return node
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func canNodeContain(n ast.Node, v ast.Node) bool {
 | 
			
		||||
	switch n.(type) {
 | 
			
		||||
	case *ast.List:
 | 
			
		||||
		return isListItem(v)
 | 
			
		||||
	case *ast.Document, *ast.BlockQuote, *ast.Aside, *ast.ListItem, *ast.CaptionFigure:
 | 
			
		||||
		return !isListItem(v)
 | 
			
		||||
	case *ast.Table:
 | 
			
		||||
		switch v.(type) {
 | 
			
		||||
		case *ast.TableHeader, *ast.TableBody, *ast.TableFooter:
 | 
			
		||||
			return true
 | 
			
		||||
		default:
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	case *ast.TableHeader, *ast.TableBody, *ast.TableFooter:
 | 
			
		||||
		_, ok := v.(*ast.TableRow)
 | 
			
		||||
		return ok
 | 
			
		||||
	case *ast.TableRow:
 | 
			
		||||
		_, ok := v.(*ast.TableCell)
 | 
			
		||||
		return ok
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) closeUnmatchedBlocks() {
 | 
			
		||||
	if p.allClosed {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for p.oldTip != p.lastMatchedContainer {
 | 
			
		||||
		parent := p.oldTip.GetParent()
 | 
			
		||||
		p.finalize(p.oldTip)
 | 
			
		||||
		p.oldTip = parent
 | 
			
		||||
	}
 | 
			
		||||
	p.allClosed = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reference represents the details of a link.
 | 
			
		||||
// See the documentation in Options for more details on use-case.
 | 
			
		||||
type Reference struct {
 | 
			
		||||
	// Link is usually the URL the reference points to.
 | 
			
		||||
	Link string
 | 
			
		||||
	// Title is the alternate text describing the link in more detail.
 | 
			
		||||
	Title string
 | 
			
		||||
	// Text is the optional text to override the ref with if the syntax used was
 | 
			
		||||
	// [refid][]
 | 
			
		||||
	Text string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse generates AST (abstract syntax tree) representing markdown document.
 | 
			
		||||
//
 | 
			
		||||
// The result is a root of the tree whose underlying type is *ast.Document
 | 
			
		||||
//
 | 
			
		||||
// You can then convert AST to html using html.Renderer, to some other format
 | 
			
		||||
// using a custom renderer or transform the tree.
 | 
			
		||||
func (p *Parser) Parse(input []byte) ast.Node {
 | 
			
		||||
	p.block(input)
 | 
			
		||||
	// Walk the tree and finish up some of unfinished blocks
 | 
			
		||||
	for p.tip != nil {
 | 
			
		||||
		p.finalize(p.tip)
 | 
			
		||||
	}
 | 
			
		||||
	// Walk the tree again and process inline markdown in each block
 | 
			
		||||
	ast.WalkFunc(p.Doc, func(node ast.Node, entering bool) ast.WalkStatus {
 | 
			
		||||
		switch node.(type) {
 | 
			
		||||
		case *ast.Paragraph, *ast.Heading, *ast.TableCell:
 | 
			
		||||
			p.Inline(node, node.AsContainer().Content)
 | 
			
		||||
			node.AsContainer().Content = nil
 | 
			
		||||
		}
 | 
			
		||||
		return ast.GoToNext
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if p.Opts.Flags&SkipFootnoteList == 0 {
 | 
			
		||||
		p.parseRefsToAST()
 | 
			
		||||
	}
 | 
			
		||||
	return p.Doc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) parseRefsToAST() {
 | 
			
		||||
	if p.extensions&Footnotes == 0 || len(p.notes) == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	p.tip = p.Doc
 | 
			
		||||
	list := &ast.List{
 | 
			
		||||
		IsFootnotesList: true,
 | 
			
		||||
		ListFlags:       ast.ListTypeOrdered,
 | 
			
		||||
	}
 | 
			
		||||
	p.addBlock(&ast.Footnotes{})
 | 
			
		||||
	block := p.addBlock(list)
 | 
			
		||||
	flags := ast.ListItemBeginningOfList
 | 
			
		||||
	// Note: this loop is intentionally explicit, not range-form. This is
 | 
			
		||||
	// because the body of the loop will append nested footnotes to p.notes and
 | 
			
		||||
	// we need to process those late additions. Range form would only walk over
 | 
			
		||||
	// the fixed initial set.
 | 
			
		||||
	for i := 0; i < len(p.notes); i++ {
 | 
			
		||||
		ref := p.notes[i]
 | 
			
		||||
		p.addChild(ref.footnote)
 | 
			
		||||
		block := ref.footnote
 | 
			
		||||
		listItem := block.(*ast.ListItem)
 | 
			
		||||
		listItem.ListFlags = flags | ast.ListTypeOrdered
 | 
			
		||||
		listItem.RefLink = ref.link
 | 
			
		||||
		if ref.hasBlock {
 | 
			
		||||
			flags |= ast.ListItemContainsBlock
 | 
			
		||||
			p.block(ref.title)
 | 
			
		||||
		} else {
 | 
			
		||||
			p.Inline(block, ref.title)
 | 
			
		||||
		}
 | 
			
		||||
		flags &^= ast.ListItemBeginningOfList | ast.ListItemContainsBlock
 | 
			
		||||
	}
 | 
			
		||||
	above := list.Parent
 | 
			
		||||
	finalizeList(list)
 | 
			
		||||
	p.tip = above
 | 
			
		||||
 | 
			
		||||
	ast.WalkFunc(block, func(node ast.Node, entering bool) ast.WalkStatus {
 | 
			
		||||
		switch node.(type) {
 | 
			
		||||
		case *ast.Paragraph, *ast.Heading:
 | 
			
		||||
			p.Inline(node, node.AsContainer().Content)
 | 
			
		||||
			node.AsContainer().Content = nil
 | 
			
		||||
		}
 | 
			
		||||
		return ast.GoToNext
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Link references
 | 
			
		||||
//
 | 
			
		||||
// This section implements support for references that (usually) appear
 | 
			
		||||
// as footnotes in a document, and can be referenced anywhere in the document.
 | 
			
		||||
// The basic format is:
 | 
			
		||||
//
 | 
			
		||||
//    [1]: http://www.google.com/ "Google"
 | 
			
		||||
//    [2]: http://www.github.com/ "Github"
 | 
			
		||||
//
 | 
			
		||||
// Anywhere in the document, the reference can be linked by referring to its
 | 
			
		||||
// label, i.e., 1 and 2 in this example, as in:
 | 
			
		||||
//
 | 
			
		||||
//    This library is hosted on [Github][2], a git hosting site.
 | 
			
		||||
//
 | 
			
		||||
// Actual footnotes as specified in Pandoc and supported by some other Markdown
 | 
			
		||||
// libraries such as php-markdown are also taken care of. They look like this:
 | 
			
		||||
//
 | 
			
		||||
//    This sentence needs a bit of further explanation.[^note]
 | 
			
		||||
//
 | 
			
		||||
//    [^note]: This is the explanation.
 | 
			
		||||
//
 | 
			
		||||
// Footnotes should be placed at the end of the document in an ordered list.
 | 
			
		||||
// Inline footnotes such as:
 | 
			
		||||
//
 | 
			
		||||
//    Inline footnotes^[Not supported.] also exist.
 | 
			
		||||
//
 | 
			
		||||
// are not yet supported.
 | 
			
		||||
 | 
			
		||||
// reference holds all information necessary for a reference-style links or
 | 
			
		||||
// footnotes.
 | 
			
		||||
//
 | 
			
		||||
// Consider this markdown with reference-style links:
 | 
			
		||||
//
 | 
			
		||||
//     [link][ref]
 | 
			
		||||
//
 | 
			
		||||
//     [ref]: /url/ "tooltip title"
 | 
			
		||||
//
 | 
			
		||||
// It will be ultimately converted to this HTML:
 | 
			
		||||
//
 | 
			
		||||
//     <p><a href=\"/url/\" title=\"title\">link</a></p>
 | 
			
		||||
//
 | 
			
		||||
// And a reference structure will be populated as follows:
 | 
			
		||||
//
 | 
			
		||||
//     p.refs["ref"] = &reference{
 | 
			
		||||
//         link: "/url/",
 | 
			
		||||
//         title: "tooltip title",
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
// Alternatively, reference can contain information about a footnote. Consider
 | 
			
		||||
// this markdown:
 | 
			
		||||
//
 | 
			
		||||
//     Text needing a footnote.[^a]
 | 
			
		||||
//
 | 
			
		||||
//     [^a]: This is the note
 | 
			
		||||
//
 | 
			
		||||
// A reference structure will be populated as follows:
 | 
			
		||||
//
 | 
			
		||||
//     p.refs["a"] = &reference{
 | 
			
		||||
//         link: "a",
 | 
			
		||||
//         title: "This is the note",
 | 
			
		||||
//         noteID: <some positive int>,
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
// TODO: As you can see, it begs for splitting into two dedicated structures
 | 
			
		||||
// for refs and for footnotes.
 | 
			
		||||
type reference struct {
 | 
			
		||||
	link     []byte
 | 
			
		||||
	title    []byte
 | 
			
		||||
	noteID   int // 0 if not a footnote ref
 | 
			
		||||
	hasBlock bool
 | 
			
		||||
	footnote ast.Node // a link to the Item node within a list of footnotes
 | 
			
		||||
 | 
			
		||||
	text []byte // only gets populated by refOverride feature with Reference.Text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *reference) String() string {
 | 
			
		||||
	return fmt.Sprintf("{link: %q, title: %q, text: %q, noteID: %d, hasBlock: %v}",
 | 
			
		||||
		r.link, r.title, r.text, r.noteID, r.hasBlock)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Check whether or not data starts with a reference link.
 | 
			
		||||
// If so, it is parsed and stored in the list of references
 | 
			
		||||
// (in the render struct).
 | 
			
		||||
// Returns the number of bytes to skip to move past it,
 | 
			
		||||
// or zero if the first line is not a reference.
 | 
			
		||||
func isReference(p *Parser, data []byte, tabSize int) int {
 | 
			
		||||
	// up to 3 optional leading spaces
 | 
			
		||||
	if len(data) < 4 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	i := 0
 | 
			
		||||
	for i < 3 && data[i] == ' ' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	noteID := 0
 | 
			
		||||
 | 
			
		||||
	// id part: anything but a newline between brackets
 | 
			
		||||
	if data[i] != '[' {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	i++
 | 
			
		||||
	if p.extensions&Footnotes != 0 {
 | 
			
		||||
		if i < len(data) && data[i] == '^' {
 | 
			
		||||
			// we can set it to anything here because the proper noteIds will
 | 
			
		||||
			// be assigned later during the second pass. It just has to be != 0
 | 
			
		||||
			noteID = 1
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	idOffset := i
 | 
			
		||||
	for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	if i >= len(data) || data[i] != ']' {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	idEnd := i
 | 
			
		||||
	// footnotes can have empty ID, like this: [^], but a reference can not be
 | 
			
		||||
	// empty like this: []. Break early if it's not a footnote and there's no ID
 | 
			
		||||
	if noteID == 0 && idOffset == idEnd {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	// spacer: colon (space | tab)* newline? (space | tab)*
 | 
			
		||||
	i++
 | 
			
		||||
	if i >= len(data) || data[i] != ':' {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	i++
 | 
			
		||||
	for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	if i < len(data) && (data[i] == '\n' || data[i] == '\r') {
 | 
			
		||||
		i++
 | 
			
		||||
		if i < len(data) && data[i] == '\n' && data[i-1] == '\r' {
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	if i >= len(data) {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		linkOffset, linkEnd   int
 | 
			
		||||
		titleOffset, titleEnd int
 | 
			
		||||
		lineEnd               int
 | 
			
		||||
		raw                   []byte
 | 
			
		||||
		hasBlock              bool
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if p.extensions&Footnotes != 0 && noteID != 0 {
 | 
			
		||||
		linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
 | 
			
		||||
		lineEnd = linkEnd
 | 
			
		||||
	} else {
 | 
			
		||||
		linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i)
 | 
			
		||||
	}
 | 
			
		||||
	if lineEnd == 0 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// a valid ref has been found
 | 
			
		||||
 | 
			
		||||
	ref := &reference{
 | 
			
		||||
		noteID:   noteID,
 | 
			
		||||
		hasBlock: hasBlock,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if noteID > 0 {
 | 
			
		||||
		// reusing the link field for the id since footnotes don't have links
 | 
			
		||||
		ref.link = data[idOffset:idEnd]
 | 
			
		||||
		// if footnote, it's not really a title, it's the contained text
 | 
			
		||||
		ref.title = raw
 | 
			
		||||
	} else {
 | 
			
		||||
		ref.link = data[linkOffset:linkEnd]
 | 
			
		||||
		ref.title = data[titleOffset:titleEnd]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// id matches are case-insensitive
 | 
			
		||||
	id := string(bytes.ToLower(data[idOffset:idEnd]))
 | 
			
		||||
 | 
			
		||||
	p.refs[id] = ref
 | 
			
		||||
 | 
			
		||||
	return lineEnd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func scanLinkRef(p *Parser, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) {
 | 
			
		||||
	// link: whitespace-free sequence, optionally between angle brackets
 | 
			
		||||
	if data[i] == '<' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	linkOffset = i
 | 
			
		||||
	for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	linkEnd = i
 | 
			
		||||
	if linkEnd < len(data) && data[linkOffset] == '<' && data[linkEnd-1] == '>' {
 | 
			
		||||
		linkOffset++
 | 
			
		||||
		linkEnd--
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// optional spacer: (space | tab)* (newline | '\'' | '"' | '(' )
 | 
			
		||||
	for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// compute end-of-line
 | 
			
		||||
	if i >= len(data) || data[i] == '\r' || data[i] == '\n' {
 | 
			
		||||
		lineEnd = i
 | 
			
		||||
	}
 | 
			
		||||
	if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' {
 | 
			
		||||
		lineEnd++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// optional (space|tab)* spacer after a newline
 | 
			
		||||
	if lineEnd > 0 {
 | 
			
		||||
		i = lineEnd + 1
 | 
			
		||||
		for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// optional title: any non-newline sequence enclosed in '"() alone on its line
 | 
			
		||||
	if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') {
 | 
			
		||||
		i++
 | 
			
		||||
		titleOffset = i
 | 
			
		||||
 | 
			
		||||
		// look for EOL
 | 
			
		||||
		for i < len(data) && data[i] != '\n' && data[i] != '\r' {
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
		if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' {
 | 
			
		||||
			titleEnd = i + 1
 | 
			
		||||
		} else {
 | 
			
		||||
			titleEnd = i
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// step back
 | 
			
		||||
		i--
 | 
			
		||||
		for i > titleOffset && (data[i] == ' ' || data[i] == '\t') {
 | 
			
		||||
			i--
 | 
			
		||||
		}
 | 
			
		||||
		if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') {
 | 
			
		||||
			lineEnd = titleEnd
 | 
			
		||||
			titleEnd = i
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The first bit of this logic is the same as Parser.listItem, but the rest
 | 
			
		||||
// is much simpler. This function simply finds the entire block and shifts it
 | 
			
		||||
// over by one tab if it is indeed a block (just returns the line if it's not).
 | 
			
		||||
// blockEnd is the end of the section in the input buffer, and contents is the
 | 
			
		||||
// extracted text that was shifted over one tab. It will need to be rendered at
 | 
			
		||||
// the end of the document.
 | 
			
		||||
func scanFootnote(p *Parser, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) {
 | 
			
		||||
	if i == 0 || len(data) == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// skip leading whitespace on first line
 | 
			
		||||
	for i < len(data) && data[i] == ' ' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	blockStart = i
 | 
			
		||||
 | 
			
		||||
	// find the end of the line
 | 
			
		||||
	blockEnd = i
 | 
			
		||||
	for i < len(data) && data[i-1] != '\n' {
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get working buffer
 | 
			
		||||
	var raw bytes.Buffer
 | 
			
		||||
 | 
			
		||||
	// put the first line into the working buffer
 | 
			
		||||
	raw.Write(data[blockEnd:i])
 | 
			
		||||
	blockEnd = i
 | 
			
		||||
 | 
			
		||||
	// process the following lines
 | 
			
		||||
	containsBlankLine := false
 | 
			
		||||
 | 
			
		||||
gatherLines:
 | 
			
		||||
	for blockEnd < len(data) {
 | 
			
		||||
		i++
 | 
			
		||||
 | 
			
		||||
		// find the end of this line
 | 
			
		||||
		for i < len(data) && data[i-1] != '\n' {
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// if it is an empty line, guess that it is part of this item
 | 
			
		||||
		// and move on to the next line
 | 
			
		||||
		if p.isEmpty(data[blockEnd:i]) > 0 {
 | 
			
		||||
			containsBlankLine = true
 | 
			
		||||
			blockEnd = i
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		n := 0
 | 
			
		||||
		if n = isIndented(data[blockEnd:i], indentSize); n == 0 {
 | 
			
		||||
			// this is the end of the block.
 | 
			
		||||
			// we don't want to include this last line in the index.
 | 
			
		||||
			break gatherLines
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// if there were blank lines before this one, insert a new one now
 | 
			
		||||
		if containsBlankLine {
 | 
			
		||||
			raw.WriteByte('\n')
 | 
			
		||||
			containsBlankLine = false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// get rid of that first tab, write to buffer
 | 
			
		||||
		raw.Write(data[blockEnd+n : i])
 | 
			
		||||
		hasBlock = true
 | 
			
		||||
 | 
			
		||||
		blockEnd = i
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if data[blockEnd-1] != '\n' {
 | 
			
		||||
		raw.WriteByte('\n')
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	contents = raw.Bytes()
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isPunctuation returns true if c is a punctuation symbol.
 | 
			
		||||
func isPunctuation(c byte) bool {
 | 
			
		||||
	for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") {
 | 
			
		||||
		if c == r {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isSpace returns true if c is a white-space charactr
 | 
			
		||||
func isSpace(c byte) bool {
 | 
			
		||||
	return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isLetter returns true if c is ascii letter
 | 
			
		||||
func isLetter(c byte) bool {
 | 
			
		||||
	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isAlnum returns true if c is a digit or letter
 | 
			
		||||
// TODO: check when this is looking for ASCII alnum and when it should use unicode
 | 
			
		||||
func isAlnum(c byte) bool {
 | 
			
		||||
	return (c >= '0' && c <= '9') || isLetter(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: this is not used
 | 
			
		||||
// Replace tab characters with spaces, aligning to the next TAB_SIZE column.
 | 
			
		||||
// always ends output with a newline
 | 
			
		||||
func expandTabs(out *bytes.Buffer, line []byte, tabSize int) {
 | 
			
		||||
	// first, check for common cases: no tabs, or only tabs at beginning of line
 | 
			
		||||
	i, prefix := 0, 0
 | 
			
		||||
	slowcase := false
 | 
			
		||||
	for i = 0; i < len(line); i++ {
 | 
			
		||||
		if line[i] == '\t' {
 | 
			
		||||
			if prefix == i {
 | 
			
		||||
				prefix++
 | 
			
		||||
			} else {
 | 
			
		||||
				slowcase = true
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// no need to decode runes if all tabs are at the beginning of the line
 | 
			
		||||
	if !slowcase {
 | 
			
		||||
		for i = 0; i < prefix*tabSize; i++ {
 | 
			
		||||
			out.WriteByte(' ')
 | 
			
		||||
		}
 | 
			
		||||
		out.Write(line[prefix:])
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// the slow case: we need to count runes to figure out how
 | 
			
		||||
	// many spaces to insert for each tab
 | 
			
		||||
	column := 0
 | 
			
		||||
	i = 0
 | 
			
		||||
	for i < len(line) {
 | 
			
		||||
		start := i
 | 
			
		||||
		for i < len(line) && line[i] != '\t' {
 | 
			
		||||
			_, size := utf8.DecodeRune(line[i:])
 | 
			
		||||
			i += size
 | 
			
		||||
			column++
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if i > start {
 | 
			
		||||
			out.Write(line[start:i])
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if i >= len(line) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for {
 | 
			
		||||
			out.WriteByte(' ')
 | 
			
		||||
			column++
 | 
			
		||||
			if column%tabSize == 0 {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Find if a line counts as indented or not.
 | 
			
		||||
// Returns number of characters the indent is (0 = not indented).
 | 
			
		||||
func isIndented(data []byte, indentSize int) int {
 | 
			
		||||
	if len(data) == 0 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	if data[0] == '\t' {
 | 
			
		||||
		return 1
 | 
			
		||||
	}
 | 
			
		||||
	if len(data) < indentSize {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < indentSize; i++ {
 | 
			
		||||
		if data[i] != ' ' {
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return indentSize
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a url-safe slug for fragments
 | 
			
		||||
func slugify(in []byte) []byte {
 | 
			
		||||
	if len(in) == 0 {
 | 
			
		||||
		return in
 | 
			
		||||
	}
 | 
			
		||||
	out := make([]byte, 0, len(in))
 | 
			
		||||
	sym := false
 | 
			
		||||
 | 
			
		||||
	for _, ch := range in {
 | 
			
		||||
		if isAlnum(ch) {
 | 
			
		||||
			sym = false
 | 
			
		||||
			out = append(out, ch)
 | 
			
		||||
		} else if sym {
 | 
			
		||||
			continue
 | 
			
		||||
		} else {
 | 
			
		||||
			out = append(out, '-')
 | 
			
		||||
			sym = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	var a, b int
 | 
			
		||||
	var ch byte
 | 
			
		||||
	for a, ch = range out {
 | 
			
		||||
		if ch != '-' {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for b = len(out) - 1; b > 0; b-- {
 | 
			
		||||
		if out[b] != '-' {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return out[a : b+1]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isListItem(d ast.Node) bool {
 | 
			
		||||
	_, ok := d.(*ast.ListItem)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								vendor/github.com/gomarkdown/markdown/parser/ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								vendor/github.com/gomarkdown/markdown/parser/ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/gomarkdown/markdown/ast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// parse '(#r)', where r does not contain spaces. Or.
 | 
			
		||||
// (!item) (!item, subitem), for an index, (!!item) signals primary.
 | 
			
		||||
func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) {
 | 
			
		||||
	if len(data[offset:]) < 4 {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
	// short ref first
 | 
			
		||||
	data = data[offset:]
 | 
			
		||||
	i := 1
 | 
			
		||||
	switch data[i] {
 | 
			
		||||
	case '#': // cross ref
 | 
			
		||||
		i++
 | 
			
		||||
	Loop:
 | 
			
		||||
		for i < len(data) {
 | 
			
		||||
			c := data[i]
 | 
			
		||||
			switch {
 | 
			
		||||
			case c == ')':
 | 
			
		||||
				break Loop
 | 
			
		||||
			case !isAlnum(c):
 | 
			
		||||
				if c == '_' || c == '-' || c == ':' {
 | 
			
		||||
					i++
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				i = 0
 | 
			
		||||
				break Loop
 | 
			
		||||
			}
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
		if i >= len(data) {
 | 
			
		||||
			return 0, nil
 | 
			
		||||
		}
 | 
			
		||||
		if data[i] != ')' {
 | 
			
		||||
			return 0, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		id := data[2:i]
 | 
			
		||||
		node := &ast.CrossReference{}
 | 
			
		||||
		node.Destination = id
 | 
			
		||||
 | 
			
		||||
		return i + 1, node
 | 
			
		||||
 | 
			
		||||
	case '!': // index
 | 
			
		||||
		i++
 | 
			
		||||
		start := i
 | 
			
		||||
		i = skipUntilChar(data, start, ')')
 | 
			
		||||
 | 
			
		||||
		// did we reach the end of the buffer without a closing marker?
 | 
			
		||||
		if i >= len(data) {
 | 
			
		||||
			return 0, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(data[start:i]) < 1 {
 | 
			
		||||
			return 0, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		idx := &ast.Index{}
 | 
			
		||||
 | 
			
		||||
		idx.ID = fmt.Sprintf("idxref:%d", p.indexCnt)
 | 
			
		||||
		p.indexCnt++
 | 
			
		||||
 | 
			
		||||
		idx.Primary = data[start] == '!'
 | 
			
		||||
		buf := data[start:i]
 | 
			
		||||
 | 
			
		||||
		if idx.Primary {
 | 
			
		||||
			buf = buf[1:]
 | 
			
		||||
		}
 | 
			
		||||
		items := bytes.Split(buf, []byte(","))
 | 
			
		||||
		switch len(items) {
 | 
			
		||||
		case 1:
 | 
			
		||||
			idx.Item = bytes.TrimSpace(items[0])
 | 
			
		||||
			return i + 1, idx
 | 
			
		||||
		case 2:
 | 
			
		||||
			idx.Item = bytes.TrimSpace(items[0])
 | 
			
		||||
			idx.Subitem = bytes.TrimSpace(items[1])
 | 
			
		||||
			return i + 1, idx
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/gomarkdown/markdown/todo.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/gomarkdown/markdown/todo.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
# Things to do
 | 
			
		||||
 | 
			
		||||
[ ] docs: add examples like https://godoc.org/github.com/dgrijalva/jwt-go (put in foo_example_test.go). Or see https://github.com/garyburd/redigo/blob/master/redis/zpop_example_test.go#L5 / https://godoc.org/github.com/garyburd/redigo/redis or https://godoc.org/github.com/go-redis/redis
 | 
			
		||||
 | 
			
		||||
[ ] figure out expandTabs and parser.TabSizeEight. Are those used?
 | 
			
		||||
 | 
			
		||||
[ ] SoftbreakData is not used
 | 
			
		||||
							
								
								
									
										189
									
								
								vendor/github.com/gomarkdown/markdown/tracking-perf.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								vendor/github.com/gomarkdown/markdown/tracking-perf.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,189 @@
 | 
			
		||||
## Tracking perf changes
 | 
			
		||||
 | 
			
		||||
Initial performance:
 | 
			
		||||
```
 | 
			
		||||
goos: darwin
 | 
			
		||||
goarch: amd64
 | 
			
		||||
pkg: github.com/gomarkdown/markdown
 | 
			
		||||
BenchmarkEscapeHTML-8                           	 2000000	       823 ns/op	       0 B/op	       0 allocs/op
 | 
			
		||||
BenchmarkSmartDoubleQuotes-8                    	  300000	      5033 ns/op	    9872 B/op	      56 allocs/op
 | 
			
		||||
BenchmarkReferenceAmps-8                        	  100000	     19538 ns/op	   26776 B/op	     150 allocs/op
 | 
			
		||||
BenchmarkReferenceAutoLinks-8                   	  100000	     17574 ns/op	   24544 B/op	     132 allocs/op
 | 
			
		||||
BenchmarkReferenceBackslashEscapes-8            	   30000	     50977 ns/op	   76752 B/op	     243 allocs/op
 | 
			
		||||
BenchmarkReferenceBlockquotesWithCodeBlocks-8   	  200000	      8546 ns/op	   12864 B/op	      65 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeBlocks-8                  	  200000	      9000 ns/op	   14912 B/op	      70 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeSpans-8                   	  200000	      8856 ns/op	   14992 B/op	      69 allocs/op
 | 
			
		||||
BenchmarkReferenceHardWrappedPara-8             	  200000	      6599 ns/op	   11312 B/op	      57 allocs/op
 | 
			
		||||
BenchmarkReferenceHorizontalRules-8             	  100000	     15483 ns/op	   23536 B/op	      98 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLAdvances-8          	  200000	      6839 ns/op	   12150 B/op	      62 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLSimple-8            	  100000	     19940 ns/op	   28488 B/op	     117 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLComments-8          	  200000	      7455 ns/op	   13440 B/op	      64 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksInline-8                 	  100000	     16425 ns/op	   23664 B/op	     147 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksReference-8              	   30000	     54895 ns/op	   66464 B/op	     416 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksShortcut-8               	  100000	     17647 ns/op	   23776 B/op	     158 allocs/op
 | 
			
		||||
BenchmarkReferenceLiterQuotesInTitles-8         	  200000	      9367 ns/op	   14832 B/op	      95 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownBasics-8              	   10000	    129772 ns/op	  130848 B/op	     378 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownSyntax-8              	    3000	    502365 ns/op	  461411 B/op	    1411 allocs/op
 | 
			
		||||
BenchmarkReferenceNestedBlockquotes-8           	  200000	      7028 ns/op	   12688 B/op	      64 allocs/op
 | 
			
		||||
BenchmarkReferenceOrderedAndUnorderedLists-8    	   20000	     79686 ns/op	  107520 B/op	     374 allocs/op
 | 
			
		||||
BenchmarkReferenceStrongAndEm-8                 	  200000	     10020 ns/op	   17792 B/op	      78 allocs/op
 | 
			
		||||
BenchmarkReferenceTabs-8                        	  200000	     12025 ns/op	   18224 B/op	      81 allocs/op
 | 
			
		||||
BenchmarkReferenceTidyness-8                    	  200000	      8985 ns/op	   14432 B/op	      71 allocs/op
 | 
			
		||||
PASS
 | 
			
		||||
ok  	github.com/gomarkdown/markdown	45.375s
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
After switching to using interface{} for Node.Data:
 | 
			
		||||
```
 | 
			
		||||
BenchmarkEscapeHTML-8                           	 2000000	       929 ns/op	       0 B/op	       0 allocs/op
 | 
			
		||||
BenchmarkSmartDoubleQuotes-8                    	  300000	      5126 ns/op	    9248 B/op	      56 allocs/op
 | 
			
		||||
BenchmarkReferenceAmps-8                        	  100000	     19927 ns/op	   17880 B/op	     154 allocs/op
 | 
			
		||||
BenchmarkReferenceAutoLinks-8                   	  100000	     20732 ns/op	   17360 B/op	     141 allocs/op
 | 
			
		||||
BenchmarkReferenceBackslashEscapes-8            	   30000	     50267 ns/op	   38128 B/op	     244 allocs/op
 | 
			
		||||
BenchmarkReferenceBlockquotesWithCodeBlocks-8   	  200000	      8988 ns/op	   10912 B/op	      67 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeBlocks-8                  	  200000	      8611 ns/op	   12256 B/op	      74 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeSpans-8                   	  200000	      8256 ns/op	   11248 B/op	      69 allocs/op
 | 
			
		||||
BenchmarkReferenceHardWrappedPara-8             	  200000	      6739 ns/op	    9856 B/op	      57 allocs/op
 | 
			
		||||
BenchmarkReferenceHorizontalRules-8             	  100000	     15503 ns/op	   15600 B/op	     104 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLAdvances-8          	  200000	      6874 ns/op	   10278 B/op	      62 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLSimple-8            	  100000	     22271 ns/op	   18552 B/op	     121 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLComments-8          	  200000	      8315 ns/op	   10736 B/op	      64 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksInline-8                 	  100000	     16155 ns/op	   16912 B/op	     152 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksReference-8              	   30000	     52387 ns/op	   38192 B/op	     445 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksShortcut-8               	  100000	     17111 ns/op	   16592 B/op	     167 allocs/op
 | 
			
		||||
BenchmarkReferenceLiterQuotesInTitles-8         	  200000	      9164 ns/op	   12048 B/op	      97 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownBasics-8              	   10000	    129262 ns/op	   87264 B/op	     416 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownSyntax-8              	    3000	    496873 ns/op	  293906 B/op	    1559 allocs/op
 | 
			
		||||
BenchmarkReferenceNestedBlockquotes-8           	  200000	      6854 ns/op	   10192 B/op	      64 allocs/op
 | 
			
		||||
BenchmarkReferenceOrderedAndUnorderedLists-8    	   20000	     79633 ns/op	   55024 B/op	     447 allocs/op
 | 
			
		||||
BenchmarkReferenceStrongAndEm-8                 	  200000	      9637 ns/op	   12176 B/op	      78 allocs/op
 | 
			
		||||
BenchmarkReferenceTabs-8                        	  100000	     12164 ns/op	   13776 B/op	      87 allocs/op
 | 
			
		||||
BenchmarkReferenceTidyness-8                    	  200000	      8677 ns/op	   11296 B/op	      75 allocs/op
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Not necessarily faster, but uses less bytes per op (but sometimes more allocs).
 | 
			
		||||
 | 
			
		||||
After tweaking the API:
 | 
			
		||||
```
 | 
			
		||||
$ ./s/run-bench.sh
 | 
			
		||||
 | 
			
		||||
go test -bench=. -test.benchmem
 | 
			
		||||
goos: darwin
 | 
			
		||||
goarch: amd64
 | 
			
		||||
pkg: github.com/gomarkdown/markdown
 | 
			
		||||
BenchmarkEscapeHTML-8                           	 2000000	       834 ns/op	       0 B/op	       0 allocs/op
 | 
			
		||||
BenchmarkSmartDoubleQuotes-8                    	  300000	      3486 ns/op	    6160 B/op	      27 allocs/op
 | 
			
		||||
BenchmarkReferenceAmps-8                        	  100000	     18158 ns/op	   14792 B/op	     125 allocs/op
 | 
			
		||||
BenchmarkReferenceAutoLinks-8                   	  100000	     16824 ns/op	   14272 B/op	     112 allocs/op
 | 
			
		||||
BenchmarkReferenceBackslashEscapes-8            	   30000	     44066 ns/op	   35040 B/op	     215 allocs/op
 | 
			
		||||
BenchmarkReferenceBlockquotesWithCodeBlocks-8   	  200000	      6868 ns/op	    7824 B/op	      38 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeBlocks-8                  	  200000	      7157 ns/op	    9168 B/op	      45 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeSpans-8                   	  200000	      6663 ns/op	    8160 B/op	      40 allocs/op
 | 
			
		||||
BenchmarkReferenceHardWrappedPara-8             	  300000	      4821 ns/op	    6768 B/op	      28 allocs/op
 | 
			
		||||
BenchmarkReferenceHorizontalRules-8             	  100000	     13033 ns/op	   12512 B/op	      75 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLAdvances-8          	  300000	      4998 ns/op	    7190 B/op	      33 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLSimple-8            	  100000	     17696 ns/op	   15464 B/op	      92 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLComments-8          	  300000	      5506 ns/op	    7648 B/op	      35 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksInline-8                 	  100000	     14450 ns/op	   13824 B/op	     123 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksReference-8              	   30000	     52561 ns/op	   35104 B/op	     416 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksShortcut-8               	  100000	     15616 ns/op	   13504 B/op	     138 allocs/op
 | 
			
		||||
BenchmarkReferenceLiterQuotesInTitles-8         	  200000	      7772 ns/op	    8960 B/op	      68 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownBasics-8              	   10000	    121436 ns/op	   84176 B/op	     387 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownSyntax-8              	    3000	    487404 ns/op	  290818 B/op	    1530 allocs/op
 | 
			
		||||
BenchmarkReferenceNestedBlockquotes-8           	  300000	      5098 ns/op	    7104 B/op	      35 allocs/op
 | 
			
		||||
BenchmarkReferenceOrderedAndUnorderedLists-8    	   20000	     74422 ns/op	   51936 B/op	     418 allocs/op
 | 
			
		||||
BenchmarkReferenceStrongAndEm-8                 	  200000	      7888 ns/op	    9088 B/op	      49 allocs/op
 | 
			
		||||
BenchmarkReferenceTabs-8                        	  200000	     10061 ns/op	   10688 B/op	      58 allocs/op
 | 
			
		||||
BenchmarkReferenceTidyness-8                    	  200000	      7152 ns/op	    8208 B/op	      46 allocs/op
 | 
			
		||||
ok  	github.com/gomarkdown/markdown	40.809s
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
After refactoring Renderer:
 | 
			
		||||
```
 | 
			
		||||
BenchmarkEscapeHTML-8                                    2000000               883 ns/op               0 B/op          0 allocs/op
 | 
			
		||||
BenchmarkSmartDoubleQuotes-8                              300000              3717 ns/op            6208 B/op         29 allocs/op
 | 
			
		||||
BenchmarkReferenceAmps-8                                  100000             19135 ns/op           14680 B/op        123 allocs/op
 | 
			
		||||
BenchmarkReferenceAutoLinks-8                             100000             17142 ns/op           14176 B/op        110 allocs/op
 | 
			
		||||
BenchmarkReferenceBackslashEscapes-8                       30000             54616 ns/op           35088 B/op        217 allocs/op
 | 
			
		||||
BenchmarkReferenceBlockquotesWithCodeBlocks-8             200000              7993 ns/op            7872 B/op         40 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeBlocks-8                            200000              8285 ns/op            9216 B/op         47 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeSpans-8                             200000              7684 ns/op            8208 B/op         42 allocs/op
 | 
			
		||||
BenchmarkReferenceHardWrappedPara-8                       200000              5595 ns/op            6816 B/op         30 allocs/op
 | 
			
		||||
BenchmarkReferenceHorizontalRules-8                       100000             16444 ns/op           12560 B/op         77 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLAdvances-8                    200000              5415 ns/op            7238 B/op         35 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLSimple-8                      100000             19867 ns/op           15512 B/op         94 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLComments-8                    200000              6026 ns/op            7696 B/op         37 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksInline-8                           100000             14864 ns/op           13664 B/op        120 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksReference-8                         30000             52479 ns/op           34816 B/op        401 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksShortcut-8                         100000             15812 ns/op           13472 B/op        135 allocs/op
 | 
			
		||||
BenchmarkReferenceLiterQuotesInTitles-8                   200000              7767 ns/op            8880 B/op         68 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownBasics-8                         10000            131065 ns/op           84048 B/op        386 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownSyntax-8                          2000            515604 ns/op          289953 B/op       1501 allocs/op
 | 
			
		||||
BenchmarkReferenceNestedBlockquotes-8                     200000              5655 ns/op            7152 B/op         37 allocs/op
 | 
			
		||||
BenchmarkReferenceOrderedAndUnorderedLists-8               20000             84188 ns/op           51984 B/op        420 allocs/op
 | 
			
		||||
BenchmarkReferenceStrongAndEm-8                           200000              8664 ns/op            9136 B/op         51 allocs/op
 | 
			
		||||
BenchmarkReferenceTabs-8                                  100000             11110 ns/op           10736 B/op         60 allocs/op
 | 
			
		||||
BenchmarkReferenceTidyness-8                              200000              7628 ns/op            8256 B/op         48 allocs/op
 | 
			
		||||
ok      github.com/gomarkdown/markdown  40.841s
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
After Node refactor to have Children array:
 | 
			
		||||
```
 | 
			
		||||
BenchmarkEscapeHTML-8                                    2000000               901 ns/op               0 B/op          0 allocs/op
 | 
			
		||||
BenchmarkSmartDoubleQuotes-8                              300000              3905 ns/op            6224 B/op         31 allocs/op
 | 
			
		||||
BenchmarkReferenceAmps-8                                  100000             22216 ns/op           15560 B/op        157 allocs/op
 | 
			
		||||
BenchmarkReferenceAutoLinks-8                             100000             20335 ns/op           14824 B/op        146 allocs/op
 | 
			
		||||
BenchmarkReferenceBackslashEscapes-8                       20000             69174 ns/op           37392 B/op        316 allocs/op
 | 
			
		||||
BenchmarkReferenceBlockquotesWithCodeBlocks-8             200000              8443 ns/op            7968 B/op         48 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeBlocks-8                            200000              9250 ns/op            9392 B/op         58 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeSpans-8                             200000              8515 ns/op            8432 B/op         54 allocs/op
 | 
			
		||||
BenchmarkReferenceHardWrappedPara-8                       200000              5738 ns/op            6856 B/op         34 allocs/op
 | 
			
		||||
BenchmarkReferenceHorizontalRules-8                       100000             20864 ns/op           13648 B/op         93 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLAdvances-8                    200000              6187 ns/op            7310 B/op         40 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLSimple-8                       50000             23793 ns/op           16128 B/op        114 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLComments-8                    200000              7060 ns/op            7840 B/op         44 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksInline-8                           100000             18432 ns/op           14496 B/op        153 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksReference-8                         20000             67666 ns/op           37136 B/op        502 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksShortcut-8                         100000             19324 ns/op           13984 B/op        162 allocs/op
 | 
			
		||||
BenchmarkReferenceLiterQuotesInTitles-8                   200000              8998 ns/op            9320 B/op         83 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownBasics-8                         10000            160908 ns/op           88152 B/op        518 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownSyntax-8                          2000            707160 ns/op          303801 B/op       2044 allocs/op
 | 
			
		||||
BenchmarkReferenceNestedBlockquotes-8                     200000              6740 ns/op            7248 B/op         45 allocs/op
 | 
			
		||||
BenchmarkReferenceOrderedAndUnorderedLists-8               10000            115808 ns/op           55052 B/op        626 allocs/op
 | 
			
		||||
BenchmarkReferenceStrongAndEm-8                           100000             10540 ns/op            9416 B/op         72 allocs/op
 | 
			
		||||
BenchmarkReferenceTabs-8                                  100000             13171 ns/op           10968 B/op         77 allocs/op
 | 
			
		||||
BenchmarkReferenceTidyness-8                              200000              8903 ns/op            8404 B/op         62 allocs/op
 | 
			
		||||
PASS
 | 
			
		||||
ok      github.com/gomarkdown/markdown  43.477s
 | 
			
		||||
```
 | 
			
		||||
It's slower (but opens up possibilities for further improvements).
 | 
			
		||||
 | 
			
		||||
After refactoring to make ast.Node a top-level thing.
 | 
			
		||||
```
 | 
			
		||||
BenchmarkEscapeHTML-8                                    2000000               829 ns/op               0 B/op          0 allocs/op
 | 
			
		||||
BenchmarkSmartDoubleQuotes-8                              300000              3998 ns/op            6192 B/op         31 allocs/op
 | 
			
		||||
BenchmarkReferenceAmps-8                                   50000             27389 ns/op           15480 B/op        153 allocs/op
 | 
			
		||||
BenchmarkReferenceAutoLinks-8                              50000             23106 ns/op           14656 B/op        137 allocs/op
 | 
			
		||||
BenchmarkReferenceBackslashEscapes-8                       10000            112435 ns/op           36696 B/op        315 allocs/op
 | 
			
		||||
BenchmarkReferenceBlockquotesWithCodeBlocks-8             200000              9227 ns/op            7856 B/op         46 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeBlocks-8                            200000             10469 ns/op            9248 B/op         54 allocs/op
 | 
			
		||||
BenchmarkReferenceCodeSpans-8                             200000             10522 ns/op            8368 B/op         54 allocs/op
 | 
			
		||||
BenchmarkReferenceHardWrappedPara-8                       200000              6354 ns/op            6784 B/op         34 allocs/op
 | 
			
		||||
BenchmarkReferenceHorizontalRules-8                        50000             32393 ns/op           13952 B/op         87 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLAdvances-8                    200000              6894 ns/op            7238 B/op         40 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLSimple-8                       50000             32942 ns/op           15864 B/op        110 allocs/op
 | 
			
		||||
BenchmarkReferenceInlineHTMLComments-8                    200000              8181 ns/op            7776 B/op         44 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksInline-8                           100000             21679 ns/op           14400 B/op        148 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksReference-8                         20000             83928 ns/op           36688 B/op        473 allocs/op
 | 
			
		||||
BenchmarkReferenceLinksShortcut-8                         100000             22053 ns/op           13872 B/op        153 allocs/op
 | 
			
		||||
BenchmarkReferenceLiterQuotesInTitles-8                   100000             10784 ns/op            9296 B/op         81 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownBasics-8                          5000            237097 ns/op           87760 B/op        480 allocs/op
 | 
			
		||||
BenchmarkReferenceMarkdownSyntax-8                          1000           1465402 ns/op          300769 B/op       1896 allocs/op
 | 
			
		||||
BenchmarkReferenceNestedBlockquotes-8                     200000              7461 ns/op            7152 B/op         45 allocs/op
 | 
			
		||||
BenchmarkReferenceOrderedAndUnorderedLists-8                5000            212256 ns/op           53724 B/op        553 allocs/op
 | 
			
		||||
BenchmarkReferenceStrongAndEm-8                           100000             13018 ns/op            9264 B/op         72 allocs/op
 | 
			
		||||
BenchmarkReferenceTabs-8                                  100000             15005 ns/op           10752 B/op         71 allocs/op
 | 
			
		||||
BenchmarkReferenceTidyness-8                              200000             10308 ns/op            8292 B/op         58 allocs/op
 | 
			
		||||
PASS
 | 
			
		||||
ok      github.com/gomarkdown/markdown  42.176s
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/matterbridge/emoji/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/matterbridge/emoji/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
.idea
 | 
			
		||||
emoji.iml
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/matterbridge/emoji/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/matterbridge/emoji/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2014 kyokomi
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
							
								
								
									
										53
									
								
								vendor/github.com/matterbridge/emoji/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								vendor/github.com/matterbridge/emoji/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
# Emoji
 | 
			
		||||
Emoji is a simple golang package.
 | 
			
		||||
 | 
			
		||||
[](https://app.wercker.com/project/byKey/7bef60de2c6d3e0e6c13d56b2393c5d8)
 | 
			
		||||
[](https://coveralls.io/r/kyokomi/emoji?branch=master)
 | 
			
		||||
[](https://godoc.org/github.com/kyokomi/emoji)
 | 
			
		||||
 | 
			
		||||
Get it:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
go get github.com/kyokomi/emoji
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Import it:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/kyokomi/emoji"
 | 
			
		||||
)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/kyokomi/emoji"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	fmt.Println("Hello World Emoji!")
 | 
			
		||||
 | 
			
		||||
	emoji.Println(":beer: Beer!!!")
 | 
			
		||||
 | 
			
		||||
	pizzaMessage := emoji.Sprint("I like a :pizza: and :sushi:!!")
 | 
			
		||||
	fmt.Println(pizzaMessage)
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Demo
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## Reference
 | 
			
		||||
 | 
			
		||||
- [GitHub EMOJI CHEAT SHEET](http://www.emoji-cheat-sheet.com/)
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
[MIT](https://github.com/kyokomi/emoji/blob/master/LICENSE)
 | 
			
		||||
							
								
								
									
										133
									
								
								vendor/github.com/matterbridge/emoji/emoji.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								vendor/github.com/matterbridge/emoji/emoji.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
			
		||||
// Package emoji terminal output.
 | 
			
		||||
package emoji
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"unicode"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//go:generate generateEmojiCodeMap -pkg emoji
 | 
			
		||||
 | 
			
		||||
// Replace Padding character for emoji.
 | 
			
		||||
const (
 | 
			
		||||
	ReplacePadding = ""
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CodeMap gets the underlying map of emoji.
 | 
			
		||||
func CodeMap() map[string]string {
 | 
			
		||||
	return emojiCodeMap
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// regular expression that matches :flag-[countrycode]:
 | 
			
		||||
var flagRegexp = regexp.MustCompile(":flag-([a-z]{2}):")
 | 
			
		||||
 | 
			
		||||
func emojize(x string) string {
 | 
			
		||||
	str, ok := emojiCodeMap[x]
 | 
			
		||||
	if ok {
 | 
			
		||||
		return str + ReplacePadding
 | 
			
		||||
	}
 | 
			
		||||
	if match := flagRegexp.FindStringSubmatch(x); len(match) == 2 {
 | 
			
		||||
		return regionalIndicator(match[1][0]) + regionalIndicator(match[1][1])
 | 
			
		||||
	}
 | 
			
		||||
	return x
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// regionalIndicator maps a lowercase letter to a unicode regional indicator
 | 
			
		||||
func regionalIndicator(i byte) string {
 | 
			
		||||
	return string('\U0001F1E6' + rune(i) - 'a')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func replaseEmoji(input *bytes.Buffer) string {
 | 
			
		||||
	emoji := bytes.NewBufferString(":")
 | 
			
		||||
	for {
 | 
			
		||||
		i, _, err := input.ReadRune()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// not replase
 | 
			
		||||
			return emoji.String()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if i == ':' && emoji.Len() == 1 {
 | 
			
		||||
			return emoji.String() + replaseEmoji(input)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		emoji.WriteRune(i)
 | 
			
		||||
		switch {
 | 
			
		||||
		case unicode.IsSpace(i):
 | 
			
		||||
			return emoji.String()
 | 
			
		||||
		case i == ':':
 | 
			
		||||
			return emojize(emoji.String())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compile(x string) string {
 | 
			
		||||
	if x == "" {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input := bytes.NewBufferString(x)
 | 
			
		||||
	output := bytes.NewBufferString("")
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		i, _, err := input.ReadRune()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		switch i {
 | 
			
		||||
		default:
 | 
			
		||||
			output.WriteRune(i)
 | 
			
		||||
		case ':':
 | 
			
		||||
			output.WriteString(replaseEmoji(input))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return output.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Print is fmt.Print which supports emoji
 | 
			
		||||
func Print(a ...interface{}) (int, error) {
 | 
			
		||||
	return fmt.Print(compile(fmt.Sprint(a...)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Println is fmt.Println which supports emoji
 | 
			
		||||
func Println(a ...interface{}) (int, error) {
 | 
			
		||||
	return fmt.Println(compile(fmt.Sprint(a...)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Printf is fmt.Printf which supports emoji
 | 
			
		||||
func Printf(format string, a ...interface{}) (int, error) {
 | 
			
		||||
	return fmt.Printf(compile(fmt.Sprintf(format, a...)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fprint is fmt.Fprint which supports emoji
 | 
			
		||||
func Fprint(w io.Writer, a ...interface{}) (int, error) {
 | 
			
		||||
	return fmt.Fprint(w, compile(fmt.Sprint(a...)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fprintln is fmt.Fprintln which supports emoji
 | 
			
		||||
func Fprintln(w io.Writer, a ...interface{}) (int, error) {
 | 
			
		||||
	return fmt.Fprintln(w, compile(fmt.Sprint(a...)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fprintf is fmt.Fprintf which supports emoji
 | 
			
		||||
func Fprintf(w io.Writer, format string, a ...interface{}) (int, error) {
 | 
			
		||||
	return fmt.Fprint(w, compile(fmt.Sprintf(format, a...)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sprint is fmt.Sprint which supports emoji
 | 
			
		||||
func Sprint(a ...interface{}) string {
 | 
			
		||||
	return compile(fmt.Sprint(a...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sprintf is fmt.Sprintf which supports emoji
 | 
			
		||||
func Sprintf(format string, a ...interface{}) string {
 | 
			
		||||
	return compile(fmt.Sprintf(format, a...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Errorf is fmt.Errorf which supports emoji
 | 
			
		||||
func Errorf(format string, a ...interface{}) error {
 | 
			
		||||
	return errors.New(compile(Sprintf(format, a...)))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4114
									
								
								vendor/github.com/matterbridge/emoji/emoji_codemap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4114
									
								
								vendor/github.com/matterbridge/emoji/emoji_codemap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										25
									
								
								vendor/github.com/matterbridge/emoji/wercker.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/matterbridge/emoji/wercker.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
box: golang
 | 
			
		||||
build:
 | 
			
		||||
  steps:
 | 
			
		||||
    - setup-go-workspace
 | 
			
		||||
    - script:
 | 
			
		||||
        name: install goveralls
 | 
			
		||||
        code: |
 | 
			
		||||
          go get github.com/mattn/goveralls
 | 
			
		||||
    - script:
 | 
			
		||||
        name: go get
 | 
			
		||||
        code: |
 | 
			
		||||
          go get ./...
 | 
			
		||||
    - script:
 | 
			
		||||
        name: go build
 | 
			
		||||
        code: |
 | 
			
		||||
          go build ./...
 | 
			
		||||
    - script:
 | 
			
		||||
        name: go test
 | 
			
		||||
        code: |
 | 
			
		||||
          go test ./...
 | 
			
		||||
    - script:
 | 
			
		||||
        name: coveralls
 | 
			
		||||
        code: |
 | 
			
		||||
          goveralls -v -service wercker.com -repotoken $COVERALLS_TOKEN
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/matterbridge/gomatrix/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/matterbridge/gomatrix/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
language: go
 | 
			
		||||
go:
 | 
			
		||||
 - 1.8
 | 
			
		||||
 - 1.10.x
 | 
			
		||||
install:
 | 
			
		||||
 - go get github.com/golang/lint/golint
 | 
			
		||||
 - go get github.com/fzipp/gocyclo
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										157
									
								
								vendor/github.com/matterbridge/gomatrix/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										157
									
								
								vendor/github.com/matterbridge/gomatrix/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -13,6 +13,7 @@ import (
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
@@ -38,6 +39,7 @@ type Client struct {
 | 
			
		||||
 | 
			
		||||
// HTTPError An HTTP Error response, which may wrap an underlying native Go Error.
 | 
			
		||||
type HTTPError struct {
 | 
			
		||||
	Contents     []byte
 | 
			
		||||
	WrappedError error
 | 
			
		||||
	Message      string
 | 
			
		||||
	Code         int
 | 
			
		||||
@@ -48,7 +50,7 @@ func (e HTTPError) Error() string {
 | 
			
		||||
	if e.WrappedError != nil {
 | 
			
		||||
		wrappedErrMsg = e.WrappedError.Error()
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("msg=%s code=%d wrapped=%s", e.Message, e.Code, wrappedErrMsg)
 | 
			
		||||
	return fmt.Sprintf("contents=%v msg=%s code=%d wrapped=%s", e.Contents, e.Message, e.Code, wrappedErrMsg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BuildURL builds a URL with the Client's homserver/prefix/access_token set already.
 | 
			
		||||
@@ -68,6 +70,10 @@ func (cli *Client) BuildBaseURL(urlPath ...string) string {
 | 
			
		||||
	parts := []string{hsURL.Path}
 | 
			
		||||
	parts = append(parts, urlPath...)
 | 
			
		||||
	hsURL.Path = path.Join(parts...)
 | 
			
		||||
	// Manually add the trailing slash back to the end of the path if it's explicitly needed
 | 
			
		||||
	if strings.HasSuffix(urlPath[len(urlPath)-1], "/") {
 | 
			
		||||
		hsURL.Path = hsURL.Path + "/"
 | 
			
		||||
	}
 | 
			
		||||
	query := hsURL.Query()
 | 
			
		||||
	if cli.AccessToken != "" {
 | 
			
		||||
		query.Set("access_token", cli.AccessToken)
 | 
			
		||||
@@ -178,27 +184,27 @@ func (cli *Client) StopSync() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MakeRequest makes a JSON HTTP request to the given URL.
 | 
			
		||||
// If "resBody" is not nil, the response body will be json.Unmarshalled into it.
 | 
			
		||||
// The response body will be stream decoded into an interface. This will automatically stop if the response
 | 
			
		||||
// body is nil.
 | 
			
		||||
//
 | 
			
		||||
// Returns the HTTP body as bytes on 2xx with a nil error. Returns an error if the response is not 2xx along
 | 
			
		||||
// with the HTTP body bytes if it got that far. This error is an HTTPError which includes the returned
 | 
			
		||||
// HTTP status code and possibly a RespError as the WrappedError, if the HTTP body could be decoded as a RespError.
 | 
			
		||||
func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{}, resBody interface{}) ([]byte, error) {
 | 
			
		||||
// Returns an error if the response is not 2xx along with the HTTP body bytes if it got that far. This error is
 | 
			
		||||
// an HTTPError which includes the returned HTTP status code, byte contents of the response body and possibly a
 | 
			
		||||
// RespError as the WrappedError, if the HTTP body could be decoded as a RespError.
 | 
			
		||||
func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{}, resBody interface{}) error {
 | 
			
		||||
	var req *http.Request
 | 
			
		||||
	var err error
 | 
			
		||||
	if reqBody != nil {
 | 
			
		||||
		var jsonStr []byte
 | 
			
		||||
		jsonStr, err = json.Marshal(reqBody)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		buf := new(bytes.Buffer)
 | 
			
		||||
		if err := json.NewEncoder(buf).Encode(reqBody); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		req, err = http.NewRequest(method, httpURL, bytes.NewBuffer(jsonStr))
 | 
			
		||||
		req, err = http.NewRequest(method, httpURL, buf)
 | 
			
		||||
	} else {
 | 
			
		||||
		req, err = http.NewRequest(method, httpURL, nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("Content-Type", "application/json")
 | 
			
		||||
	res, err := cli.Client.Do(req)
 | 
			
		||||
@@ -206,10 +212,14 @@ func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{
 | 
			
		||||
		defer res.Body.Close()
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	contents, err := ioutil.ReadAll(res.Body)
 | 
			
		||||
	if res.StatusCode/100 != 2 { // not 2xx
 | 
			
		||||
		contents, err := ioutil.ReadAll(res.Body)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var wrap error
 | 
			
		||||
		var respErr RespError
 | 
			
		||||
		if _ = json.Unmarshal(contents, &respErr); respErr.ErrCode != "" {
 | 
			
		||||
@@ -223,29 +233,25 @@ func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{
 | 
			
		||||
			msg = msg + ": " + string(contents)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return contents, HTTPError{
 | 
			
		||||
		return HTTPError{
 | 
			
		||||
			Contents:     contents,
 | 
			
		||||
			Code:         res.StatusCode,
 | 
			
		||||
			Message:      msg,
 | 
			
		||||
			WrappedError: wrap,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
 | 
			
		||||
	if resBody != nil && res.Body != nil {
 | 
			
		||||
		return json.NewDecoder(res.Body).Decode(&resBody)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if resBody != nil {
 | 
			
		||||
		if err = json.Unmarshal(contents, &resBody); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return contents, nil
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateFilter makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-user-userid-filter
 | 
			
		||||
func (cli *Client) CreateFilter(filter json.RawMessage) (resp *RespCreateFilter, err error) {
 | 
			
		||||
	urlPath := cli.BuildURL("user", cli.UserID, "filter")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", urlPath, &filter, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", urlPath, &filter, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -267,13 +273,12 @@ func (cli *Client) SyncRequest(timeout int, since, filterID string, fullState bo
 | 
			
		||||
		query["full_state"] = "true"
 | 
			
		||||
	}
 | 
			
		||||
	urlPath := cli.BuildURLWithQuery([]string{"sync"}, query)
 | 
			
		||||
	_, err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cli *Client) register(u string, req *ReqRegister) (resp *RespRegister, uiaResp *RespUserInteractive, err error) {
 | 
			
		||||
	var bodyBytes []byte
 | 
			
		||||
	bodyBytes, err = cli.MakeRequest("POST", u, req, nil)
 | 
			
		||||
	err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		httpErr, ok := err.(HTTPError)
 | 
			
		||||
		if !ok { // network error
 | 
			
		||||
@@ -281,13 +286,10 @@ func (cli *Client) register(u string, req *ReqRegister) (resp *RespRegister, uia
 | 
			
		||||
		}
 | 
			
		||||
		if httpErr.Code == 401 {
 | 
			
		||||
			// body should be RespUserInteractive, if it isn't, fail with the error
 | 
			
		||||
			err = json.Unmarshal(bodyBytes, &uiaResp)
 | 
			
		||||
			err = json.Unmarshal(httpErr.Contents, &uiaResp)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// body should be RespRegister
 | 
			
		||||
	err = json.Unmarshal(bodyBytes, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -351,7 +353,7 @@ func (cli *Client) RegisterDummy(req *ReqRegister) (*RespRegister, error) {
 | 
			
		||||
// This does not set credentials on this client instance. See SetCredentials() instead.
 | 
			
		||||
func (cli *Client) Login(req *ReqLogin) (resp *RespLogin, err error) {
 | 
			
		||||
	urlPath := cli.BuildURL("login")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", urlPath, req, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", urlPath, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -359,14 +361,14 @@ func (cli *Client) Login(req *ReqLogin) (resp *RespLogin, err error) {
 | 
			
		||||
// This does not clear the credentials from the client instance. See ClearCredentials() instead.
 | 
			
		||||
func (cli *Client) Logout() (resp *RespLogout, err error) {
 | 
			
		||||
	urlPath := cli.BuildURL("logout")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", urlPath, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", urlPath, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Versions returns the list of supported Matrix versions on this homeserver. See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions
 | 
			
		||||
func (cli *Client) Versions() (resp *RespVersions, err error) {
 | 
			
		||||
	urlPath := cli.BuildBaseURL("_matrix", "client", "versions")
 | 
			
		||||
	_, err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -383,21 +385,21 @@ func (cli *Client) JoinRoom(roomIDorAlias, serverName string, content interface{
 | 
			
		||||
	} else {
 | 
			
		||||
		urlPath = cli.BuildURL("join", roomIDorAlias)
 | 
			
		||||
	}
 | 
			
		||||
	_, err = cli.MakeRequest("POST", urlPath, content, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", urlPath, content, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetDisplayName returns the display name of the user from the specified MXID. See https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
 | 
			
		||||
func (cli *Client) GetDisplayName(mxid string) (resp *RespUserDisplayName, err error) {
 | 
			
		||||
	urlPath := cli.BuildURL("profile", mxid, "displayname")
 | 
			
		||||
	_, err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOwnDisplayName returns the user's display name. See https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
 | 
			
		||||
func (cli *Client) GetOwnDisplayName() (resp *RespUserDisplayName, err error) {
 | 
			
		||||
	urlPath := cli.BuildURL("profile", cli.UserID, "displayname")
 | 
			
		||||
	_, err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -407,18 +409,18 @@ func (cli *Client) SetDisplayName(displayName string) (err error) {
 | 
			
		||||
	s := struct {
 | 
			
		||||
		DisplayName string `json:"displayname"`
 | 
			
		||||
	}{displayName}
 | 
			
		||||
	_, err = cli.MakeRequest("PUT", urlPath, &s, nil)
 | 
			
		||||
	err = cli.MakeRequest("PUT", urlPath, &s, nil)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetAvatarURL gets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-avatar-url
 | 
			
		||||
func (cli *Client) GetAvatarURL() (url string, err error) {
 | 
			
		||||
func (cli *Client) GetAvatarURL() (string, error) {
 | 
			
		||||
	urlPath := cli.BuildURL("profile", cli.UserID, "avatar_url")
 | 
			
		||||
	s := struct {
 | 
			
		||||
		AvatarURL string `json:"avatar_url"`
 | 
			
		||||
	}{}
 | 
			
		||||
 | 
			
		||||
	_, err = cli.MakeRequest("GET", urlPath, nil, &s)
 | 
			
		||||
	err := cli.MakeRequest("GET", urlPath, nil, &s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
@@ -427,12 +429,12 @@ func (cli *Client) GetAvatarURL() (url string, err error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetAvatarURL sets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-profile-userid-avatar-url
 | 
			
		||||
func (cli *Client) SetAvatarURL(url string) (err error) {
 | 
			
		||||
func (cli *Client) SetAvatarURL(url string) error {
 | 
			
		||||
	urlPath := cli.BuildURL("profile", cli.UserID, "avatar_url")
 | 
			
		||||
	s := struct {
 | 
			
		||||
		AvatarURL string `json:"avatar_url"`
 | 
			
		||||
	}{url}
 | 
			
		||||
	_, err = cli.MakeRequest("PUT", urlPath, &s, nil)
 | 
			
		||||
	err := cli.MakeRequest("PUT", urlPath, &s, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -445,7 +447,7 @@ func (cli *Client) SetAvatarURL(url string) (err error) {
 | 
			
		||||
func (cli *Client) SendMessageEvent(roomID string, eventType string, contentJSON interface{}) (resp *RespSendEvent, err error) {
 | 
			
		||||
	txnID := txnID()
 | 
			
		||||
	urlPath := cli.BuildURL("rooms", roomID, "send", eventType, txnID)
 | 
			
		||||
	_, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
 | 
			
		||||
	err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -453,7 +455,7 @@ func (cli *Client) SendMessageEvent(roomID string, eventType string, contentJSON
 | 
			
		||||
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
 | 
			
		||||
func (cli *Client) SendStateEvent(roomID, eventType, stateKey string, contentJSON interface{}) (resp *RespSendEvent, err error) {
 | 
			
		||||
	urlPath := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
 | 
			
		||||
	_, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
 | 
			
		||||
	err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -491,6 +493,36 @@ func (cli *Client) SendVideo(roomID, body, url string) (*RespSendEvent, error) {
 | 
			
		||||
		})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SendAudio sends an m.room.message event into the given room with a msgtype of m.audio
 | 
			
		||||
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-audio
 | 
			
		||||
func (cli *Client) SendAudio(roomID, body, url, mimetype string, size uint) (*RespSendEvent, error) {
 | 
			
		||||
	return cli.SendMessageEvent(roomID, "m.room.message",
 | 
			
		||||
		AudioMessage{
 | 
			
		||||
			MsgType: "m.audio",
 | 
			
		||||
			Body:    body,
 | 
			
		||||
			URL:     url,
 | 
			
		||||
			Info: AudioInfo{
 | 
			
		||||
				Size:     size,
 | 
			
		||||
				Mimetype: mimetype,
 | 
			
		||||
			},
 | 
			
		||||
		})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SendFile sends an m.room.message event into the given room with a msgtype of m.file
 | 
			
		||||
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-file
 | 
			
		||||
func (cli *Client) SendFile(roomID, body, url, mimetype string, size uint) (*RespSendEvent, error) {
 | 
			
		||||
	return cli.SendMessageEvent(roomID, "m.room.message",
 | 
			
		||||
		FileMessage{
 | 
			
		||||
			MsgType: "m.file",
 | 
			
		||||
			Body:    body,
 | 
			
		||||
			URL:     url,
 | 
			
		||||
			Info: FileInfo{
 | 
			
		||||
				Size:     size,
 | 
			
		||||
				Mimetype: mimetype,
 | 
			
		||||
			},
 | 
			
		||||
		})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SendNotice sends an m.room.message event into the given room with a msgtype of m.notice
 | 
			
		||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-notice
 | 
			
		||||
func (cli *Client) SendNotice(roomID, text string) (*RespSendEvent, error) {
 | 
			
		||||
@@ -507,7 +539,7 @@ func (cli *Client) SendNoticeHTML(roomID, textclear, text string) (*RespSendEven
 | 
			
		||||
func (cli *Client) RedactEvent(roomID, eventID string, req *ReqRedact) (resp *RespSendEvent, err error) {
 | 
			
		||||
	txnID := txnID()
 | 
			
		||||
	urlPath := cli.BuildURL("rooms", roomID, "redact", eventID, txnID)
 | 
			
		||||
	_, err = cli.MakeRequest("PUT", urlPath, req, &resp)
 | 
			
		||||
	err = cli.MakeRequest("PUT", urlPath, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -518,56 +550,56 @@ func (cli *Client) RedactEvent(roomID, eventID string, req *ReqRedact) (resp *Re
 | 
			
		||||
//  fmt.Println("Room:", resp.RoomID)
 | 
			
		||||
func (cli *Client) CreateRoom(req *ReqCreateRoom) (resp *RespCreateRoom, err error) {
 | 
			
		||||
	urlPath := cli.BuildURL("createRoom")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", urlPath, req, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", urlPath, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LeaveRoom leaves the given room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-leave
 | 
			
		||||
func (cli *Client) LeaveRoom(roomID string) (resp *RespLeaveRoom, err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "leave")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", u, struct{}{}, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", u, struct{}{}, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ForgetRoom forgets a room entirely. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-forget
 | 
			
		||||
func (cli *Client) ForgetRoom(roomID string) (resp *RespForgetRoom, err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "forget")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", u, struct{}{}, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", u, struct{}{}, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InviteUser invites a user to a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
 | 
			
		||||
func (cli *Client) InviteUser(roomID string, req *ReqInviteUser) (resp *RespInviteUser, err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "invite")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", u, struct{}{}, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InviteUserByThirdParty invites a third-party identifier to a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#invite-by-third-party-id-endpoint
 | 
			
		||||
func (cli *Client) InviteUserByThirdParty(roomID string, req *ReqInvite3PID) (resp *RespInviteUser, err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "invite")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KickUser kicks a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
 | 
			
		||||
func (cli *Client) KickUser(roomID string, req *ReqKickUser) (resp *RespKickUser, err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "kick")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BanUser bans a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
 | 
			
		||||
func (cli *Client) BanUser(roomID string, req *ReqBanUser) (resp *RespBanUser, err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "ban")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnbanUser unbans a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
 | 
			
		||||
func (cli *Client) UnbanUser(roomID string, req *ReqUnbanUser) (resp *RespUnbanUser, err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "unban")
 | 
			
		||||
	_, err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	err = cli.MakeRequest("POST", u, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -575,7 +607,7 @@ func (cli *Client) UnbanUser(roomID string, req *ReqUnbanUser) (resp *RespUnbanU
 | 
			
		||||
func (cli *Client) UserTyping(roomID string, typing bool, timeout int64) (resp *RespTyping, err error) {
 | 
			
		||||
	req := ReqTyping{Typing: typing, Timeout: timeout}
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "typing", cli.UserID)
 | 
			
		||||
	_, err = cli.MakeRequest("PUT", u, req, &resp)
 | 
			
		||||
	err = cli.MakeRequest("PUT", u, req, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -584,7 +616,7 @@ func (cli *Client) UserTyping(roomID string, typing bool, timeout int64) (resp *
 | 
			
		||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey
 | 
			
		||||
func (cli *Client) StateEvent(roomID, eventType, stateKey string, outContent interface{}) (err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
 | 
			
		||||
	_, err = cli.MakeRequest("GET", u, nil, outContent)
 | 
			
		||||
	err = cli.MakeRequest("GET", u, nil, outContent)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -625,8 +657,9 @@ func (cli *Client) UploadToContentRepo(content io.Reader, contentType string, co
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil, HTTPError{
 | 
			
		||||
			Message: "Upload request failed: " + string(contents),
 | 
			
		||||
			Code:    res.StatusCode,
 | 
			
		||||
			Contents: contents,
 | 
			
		||||
			Message:  "Upload request failed: " + string(contents),
 | 
			
		||||
			Code:     res.StatusCode,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	var m RespMediaUpload
 | 
			
		||||
@@ -642,7 +675,7 @@ func (cli *Client) UploadToContentRepo(content io.Reader, contentType string, co
 | 
			
		||||
// This API is primarily designed for application services which may want to efficiently look up joined members in a room.
 | 
			
		||||
func (cli *Client) JoinedMembers(roomID string) (resp *RespJoinedMembers, err error) {
 | 
			
		||||
	u := cli.BuildURL("rooms", roomID, "joined_members")
 | 
			
		||||
	_, err = cli.MakeRequest("GET", u, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("GET", u, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -652,7 +685,7 @@ func (cli *Client) JoinedMembers(roomID string) (resp *RespJoinedMembers, err er
 | 
			
		||||
// This API is primarily designed for application services which may want to efficiently look up joined rooms.
 | 
			
		||||
func (cli *Client) JoinedRooms() (resp *RespJoinedRooms, err error) {
 | 
			
		||||
	u := cli.BuildURL("joined_rooms")
 | 
			
		||||
	_, err = cli.MakeRequest("GET", u, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("GET", u, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -672,7 +705,7 @@ func (cli *Client) Messages(roomID, from, to string, dir rune, limit int) (resp
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "messages"}, query)
 | 
			
		||||
	_, err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -680,7 +713,7 @@ func (cli *Client) Messages(roomID, from, to string, dir rune, limit int) (resp
 | 
			
		||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-voip-turnserver
 | 
			
		||||
func (cli *Client) TurnServer() (resp *RespTurnServer, err error) {
 | 
			
		||||
	urlPath := cli.BuildURL("voip", "turnServer")
 | 
			
		||||
	_, err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	err = cli.MakeRequest("GET", urlPath, nil, &resp)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user