Compare commits
12
Commits
3.1i
...
b926173f43
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b926173f43 | ||
|
|
2667b0ccfd | ||
|
|
3aa8054dc0 | ||
|
|
ad9a0ea9a8 | ||
|
|
de40a5dec8 | ||
|
|
78c7f0175d | ||
|
|
7bab52f033 | ||
|
|
652fd3ea19 | ||
|
|
536ce4cae6 | ||
|
|
202e3ba6b1 | ||
|
|
7f01f38436 | ||
|
|
4afe2de35d |
No files matched your search
@@ -112,7 +112,7 @@ go build -tags wayland .
|
||||
## εγκατάσταση
|
||||
(installation)
|
||||
|
||||
pi currently has no consolidated way of installing it. There is an [Arch User Repository package available](https://aur.archlinux.org/pi-im), which is maintained by [snit](https://isekai.rocks/~snit).
|
||||
pi currently has no consolidated way of installing it. There is an [Arch User Repository package available](https://aur.archlinux.org/packages/pi-im), which is maintained by [snit](https://isekai.rocks/~snit).
|
||||
|
||||
## υποστήριξη
|
||||
(support)
|
||||
|
||||
@@ -3,19 +3,20 @@ package main
|
||||
import (
|
||||
//core - required
|
||||
"context"
|
||||
_ "embed"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand/v2"
|
||||
"net/url"
|
||||
"image/color"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
_ "embed"
|
||||
_ "image/png"
|
||||
_ "image/jpeg"
|
||||
|
||||
// gui - required
|
||||
"fyne.io/fyne/v2"
|
||||
@@ -27,25 +28,25 @@ import (
|
||||
"fyne.io/fyne/v2/storage"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
extraWidgets "fyne.io/x/fyne/widget"
|
||||
"github.com/makeworld-the-better-one/go-isemoji"
|
||||
"github.com/rrivera/identicon"
|
||||
"github.com/shreve/musicwand/pkg/mpris"
|
||||
|
||||
// xmpp - required
|
||||
oasisSdk "github.com/sunglocto/oasis-sdk"
|
||||
"mellium.im/xmpp/bookmarks"
|
||||
"mellium.im/xmpp/jid"
|
||||
"mellium.im/xmpp/muc"
|
||||
"mellium.im/xmpp/stanza"
|
||||
"mellium.im/xmpp/pubsub"
|
||||
oasisSdk "github.com/sunglocto/oasis-sdk"
|
||||
"mellium.im/xmpp/stanza"
|
||||
xmppColor "mellium.im/xmpp/color"
|
||||
// TODO: integrated theme switcher
|
||||
)
|
||||
|
||||
//go:embed pi.png
|
||||
var iconBytes []byte
|
||||
|
||||
var version string = "3.1i"
|
||||
var version string = "3.14i"
|
||||
var statBar widget.Label
|
||||
var chatInfo fyne.Container
|
||||
var chatSidebar fyne.Container
|
||||
@@ -167,14 +168,14 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
im := ii.Image(25)
|
||||
ico := canvas.NewImageFromImage(im)
|
||||
ico.FillMode = canvas.ImageFillOriginal
|
||||
author := widget.NewLabel("author")
|
||||
author := canvas.NewText("author", color.RGBA{255, 255, 255, 255})
|
||||
author.TextStyle.Bold = true
|
||||
author.Selectable = true
|
||||
// author.Selectable = true
|
||||
content := widget.NewLabel("content")
|
||||
content.Wrapping = fyne.TextWrapWord
|
||||
content.Selectable = true
|
||||
content.Importance = widget.MediumImportance
|
||||
//content.SizeName = fyne.ThemeSizeName(theme.SizeNameText)
|
||||
content.SizeName = fyne.ThemeSizeName(theme.SizeNameText)
|
||||
icon := theme.FileVideoIcon()
|
||||
replytext := widget.NewLabel(">fallback reply text")
|
||||
replytext.Hide()
|
||||
@@ -207,7 +208,10 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
|
||||
// Icon generate end
|
||||
|
||||
author := authorBox.Objects[1].(*widget.Label)
|
||||
author := authorBox.Objects[1].(*canvas.Text)
|
||||
col := xmppColor.String(chatTabs[chatJidStr].Messages[i].Author, 0, xmppColor.None)
|
||||
author.Color = col
|
||||
|
||||
content := vbox.Objects[2].(*widget.Label)
|
||||
unknown_tags := chatTabs[chatJidStr].Messages[i].Raw.Unknown
|
||||
for _, v := range unknown_tags {
|
||||
@@ -216,8 +220,9 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
if attr.Name.Local == "id" {
|
||||
reason, ok := OccupantIdsToBlock[attr.Value]
|
||||
if ok {
|
||||
author.SetText("Ignored user")
|
||||
author.Text = ("Ignored user")
|
||||
content.SetText("This user is ignored due to: " + reason)
|
||||
content.Importance = widget.LowImportance
|
||||
return // message is from blocked user
|
||||
}
|
||||
}
|
||||
@@ -236,6 +241,8 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
|
||||
if chatTabs[chatJidStr].Messages[i].Important {
|
||||
content.Importance = widget.DangerImportance
|
||||
} else {
|
||||
content.Importance = widget.MediumImportance
|
||||
}
|
||||
btn.Hidden = true // Hide by default
|
||||
msgContent := chatTabs[chatJidStr].Messages[i].Content
|
||||
@@ -296,27 +303,31 @@ func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
for i := len(chatTabs[chatJidStr].Messages) - 1; i >= 0; i-- {
|
||||
if reply.ID == chatTabs[chatJidStr].Messages[i].Raw.StanzaID.ID {
|
||||
replytext.Show()
|
||||
replytext.SetText(fmt.Sprintf("%s %s", replyBodyIcon, strings.ReplaceAll(chatTabs[chatJidStr].Messages[i].Content, "\n", newlineIcon)))
|
||||
replytext.Text = fmt.Sprintf("%s %s", replyBodyIcon, strings.ReplaceAll(chatTabs[chatJidStr].Messages[i].Content, "\n", newlineIcon))
|
||||
guy = chatTabs[chatJidStr].Messages[i].Author
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
author.SetText(fmt.Sprintf("%s %s %s", chatTabs[chatJidStr].Messages[i].Author, replyNameIcon, guy))
|
||||
author.Text = (fmt.Sprintf("%s %s %s", chatTabs[chatJidStr].Messages[i].Author, replyNameIcon, guy))
|
||||
} else {
|
||||
author.SetText(chatTabs[chatJidStr].Messages[i].Author)
|
||||
author.Text = (chatTabs[chatJidStr].Messages[i].Author)
|
||||
replytext.Hide()
|
||||
}
|
||||
|
||||
sl := strings.Split(msgContent, " ")
|
||||
|
||||
content.SizeName = fyne.ThemeSizeName(theme.SizeNameText)
|
||||
if len(sl) == 1 && isemoji.IsEmoji(sl[0]) {
|
||||
content.SizeName = fyne.ThemeSizeName(theme.SizeNameHeadingText)
|
||||
content.Refresh()
|
||||
} else {
|
||||
content.SizeName = fyne.ThemeSizeName(theme.SizeNameText)
|
||||
content.Refresh()
|
||||
}
|
||||
|
||||
if sl[0] == "/me" {
|
||||
author.SetText(author.Text + " " + strings.Join(sl[1:], " "))
|
||||
author.Text = (author.Text + " " + strings.Join(sl[1:], " "))
|
||||
content.SetText(" ")
|
||||
}
|
||||
|
||||
@@ -797,6 +808,7 @@ func main() {
|
||||
}, w)
|
||||
})
|
||||
w.Resize(fyne.NewSize(500, 500))
|
||||
w.SetIcon(res)
|
||||
|
||||
entry := NewCustomMultiLineEntry()
|
||||
entry.SetPlaceHolder("Say something, you know you want to.\nCtrl+Enter for newline")
|
||||
@@ -1170,19 +1182,19 @@ func main() {
|
||||
|
||||
setNick = widget.NewButton("Set nick", func() {
|
||||
go func() {
|
||||
fyne.Do(func() {setNick.Disable()})
|
||||
newNick := nickEntry.Text
|
||||
bookmark.Nick = newNick
|
||||
err := client.PublishBookmark(bookmark, context.TODO())
|
||||
if err != nil {
|
||||
fyne.Do(func() {
|
||||
setNick.Enable()
|
||||
dialog.ShowError(err, w)
|
||||
})
|
||||
return
|
||||
}
|
||||
client.RefreshBookmarks(false)
|
||||
fyne.Do(func() {setNick.Enable()})
|
||||
fyne.Do(func() { setNick.Disable() })
|
||||
newNick := nickEntry.Text
|
||||
bookmark.Nick = newNick
|
||||
err := client.PublishBookmark(bookmark, context.TODO())
|
||||
if err != nil {
|
||||
fyne.Do(func() {
|
||||
setNick.Enable()
|
||||
dialog.ShowError(err, w)
|
||||
})
|
||||
return
|
||||
}
|
||||
client.RefreshBookmarks(false)
|
||||
fyne.Do(func() { setNick.Enable() })
|
||||
}()
|
||||
})
|
||||
|
||||
@@ -1206,14 +1218,7 @@ func main() {
|
||||
|
||||
joinARoom := fyne.NewMenuItem("connect to a room", func() {
|
||||
dialog.ShowEntryDialog("connect to a room", "JID:", func(s string) {
|
||||
i := resourcePiloadingGif
|
||||
gif, err := extraWidgets.NewAnimatedGifFromResource(i)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gif.Start()
|
||||
gif.Show()
|
||||
d := dialog.NewCustom("Please wait", "Close", gif, w)
|
||||
d := dialog.NewCustom("Please wait", "Close", widget.NewLabel("Connecting to "+s), w)
|
||||
d.Show()
|
||||
go func() {
|
||||
myjid, err := jid.Parse(s)
|
||||
@@ -1242,14 +1247,7 @@ func main() {
|
||||
|
||||
beginADM := fyne.NewMenuItem("start a DM", func() {
|
||||
dialog.ShowEntryDialog("Start a DM", "JID:", func(s string) {
|
||||
i := resourcePiloadingGif
|
||||
gif, err := extraWidgets.NewAnimatedGifFromResource(i)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gif.Start()
|
||||
gif.Show()
|
||||
d := dialog.NewCustom("Please wait", "Close", gif, w)
|
||||
d := dialog.NewCustom("Please wait", "Close", widget.NewLabel("Opening a DM with " + s), w)
|
||||
d.Show()
|
||||
go func() {
|
||||
myjid, err := jid.Parse(s)
|
||||
@@ -1300,6 +1298,8 @@ func main() {
|
||||
entry.Text = old
|
||||
})
|
||||
|
||||
|
||||
|
||||
kai := fyne.NewMenuItem("kai cenat beg", func() {
|
||||
old := entry.Text
|
||||
entry.Text = "chat will you subscribe to save the kai cenat mafiathon 3"
|
||||
@@ -1314,6 +1314,13 @@ func main() {
|
||||
entry.Text = old
|
||||
})
|
||||
|
||||
wspeed := fyne.NewMenuItem("W Speed ❤️🩹❤️🩹", func() {
|
||||
old := entry.Text
|
||||
entry.Text = "W Speed ❤️🩹❤️🩹"
|
||||
SendCallback()
|
||||
entry.Text = old
|
||||
})
|
||||
|
||||
exposed_suffix := fyne.NewMenuItem(".exposed", func() {
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
@@ -1390,7 +1397,7 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
menu_jokes := fyne.NewMenu("Δ", mycurrenttime, mycurrentplayingsong, hafjag, hotfuck, agree, kai, mipipiemi, exposed_suffix)
|
||||
menu_jokes := fyne.NewMenu("Δ", mycurrenttime, mycurrentplayingsong, hafjag, hotfuck, agree, kai, mipipiemi, exposed_suffix, wspeed)
|
||||
bit := fyne.NewMenuItem("mark selected message as read", func() {
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
@@ -1408,6 +1415,36 @@ func main() {
|
||||
client.MarkAsRead(&m)
|
||||
})
|
||||
|
||||
rec := fyne.NewMenuItem("retract selected message", func() {
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var activeMucJid string
|
||||
for jid, tabData := range UITabs {
|
||||
if tabData.Scroller == selectedScroller {
|
||||
activeMucJid = jid
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !chatTabs[activeMucJid].isMuc {
|
||||
return // TODO: For 1:1 DMs we use OccupantID for the ID and send message type 'chat'
|
||||
}
|
||||
|
||||
id := chatTabs[activeMucJid].Messages[selectedId].Raw.StanzaID
|
||||
if id == nil {
|
||||
return
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("<message type='groupchat' to='%s' id='retract-message-1'><retract id='%s' xmlns='urn:xmpp:message-retract:1'/><fallback xmlns='urn:xmpp:fallback:0' for='urn:xmpp:message-retract:1' /><body>This user retracted a previous message, but it's unsupported by your client.</body><store xmlns='urn:xmpp:hints'/></message>", activeMucJid, id.ID)
|
||||
fmt.Println(msg)
|
||||
err := client.Session.Send(context.TODO(), xml.NewDecoder(strings.NewReader(msg)))
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
})
|
||||
|
||||
bia := fyne.NewMenuItem("toggle replying to message", func() {
|
||||
replying = !replying
|
||||
})
|
||||
@@ -1517,7 +1554,7 @@ func main() {
|
||||
dialog.ShowCustom("Message", "Close", pre, w)
|
||||
})
|
||||
|
||||
menu_messageoptions := fyne.NewMenu("Γ", bit, bia, bic, red, blck)
|
||||
menu_messageoptions := fyne.NewMenu("Γ", bit, bia, bic, rec, red, blck)
|
||||
ma := fyne.NewMainMenu(menu_help, menu_changeroom, menu_configureview, menu_messageoptions, menu_jokes)
|
||||
w.SetMainMenu(ma)
|
||||
|
||||
@@ -1558,9 +1595,9 @@ func main() {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
fyne.Do(func() {
|
||||
AppTabs.Selected().Text = fmt.Sprintf("%s (disconnected)", AppTabs.Selected().Text)
|
||||
AppTabs.Remove(ti)
|
||||
delete(UITabs, activeChatJid)
|
||||
AppTabs.Selected().Text = fmt.Sprintf("%s (disconnected)", AppTabs.Selected().Text)
|
||||
AppTabs.Remove(ti)
|
||||
delete(UITabs, activeChatJid)
|
||||
})
|
||||
}()
|
||||
}
|
||||
@@ -1573,6 +1610,16 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
AppTabs.OnUnselected = func(ti *container.TabItem) {
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
selectedScroller.Hidden = true
|
||||
}
|
||||
|
||||
var MainSplit *container.Split
|
||||
|
||||
AppTabs.OnSelected = func(ti *container.TabItem) {
|
||||
chatSidebar.Resize(chatSidebar.Size())
|
||||
if AppTabs.Selected() == AppTabs.Items[0] {
|
||||
@@ -1584,6 +1631,8 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
selectedScroller.Hidden = false
|
||||
|
||||
var activeChatJid string
|
||||
for jid, tabData := range UITabs {
|
||||
if tabData.Scroller == selectedScroller {
|
||||
@@ -1601,8 +1650,8 @@ func main() {
|
||||
nameLabel.Truncation = fyne.TextTruncateEllipsis
|
||||
memberLabel := widget.NewLabel(fmt.Sprintf("%d members ", len(tab.Members)))
|
||||
memberLabel.Truncation = fyne.TextTruncateEllipsis
|
||||
box := container.NewVBox(nameLabel, )
|
||||
chatSidebar.Objects = []fyne.CanvasObject{}
|
||||
box := container.NewVBox(nameLabel)
|
||||
// chatSidebar.Objects = []fyne.CanvasObject{}
|
||||
|
||||
for name, p := range tab.Members {
|
||||
log.Println(string(p.Type))
|
||||
@@ -1644,24 +1693,28 @@ func main() {
|
||||
}
|
||||
s.Truncation = fyne.TextTruncateEllipsis
|
||||
box.Add(s)
|
||||
box.Refresh()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
chatSidebar = *container.NewGridWithColumns(1, container.NewVScroll(box))
|
||||
} else {
|
||||
chatSidebar = *container.NewVBox(widget.NewRichTextFromMarkdown("# " + activeChatJid))
|
||||
if activeChatJid == config.Login.User {
|
||||
chatSidebar = *container.NewVBox(widget.NewRichTextFromMarkdown("# " + activeChatJid), widget.NewLabel("Hey, that's you!"))
|
||||
} else {
|
||||
chatSidebar = *container.NewVBox(widget.NewRichTextFromMarkdown("# " + activeChatJid))
|
||||
}
|
||||
}
|
||||
chatSidebar.Hidden = false
|
||||
chatSidebar.Refresh()
|
||||
chatSidebar.Resize(chatSidebar.Size())
|
||||
|
||||
chatSidebar.Show()
|
||||
MainSplit.Resize(MainSplit.Size())
|
||||
}
|
||||
|
||||
chatSidebar.Hidden = false
|
||||
statBar.SetText("")
|
||||
chatInfo = *container.NewHBox(widget.NewLabel(""))
|
||||
MainSplit := container.NewHSplit(AppTabs, &chatSidebar)
|
||||
MainSplit = container.NewHSplit(AppTabs, &chatSidebar)
|
||||
DownSplit := container.NewHSplit(entry, container.NewGridWithRows(1, sendbtn, replybtn))
|
||||
|
||||
BigSplit := container.NewVSplit(MainSplit, DownSplit)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// auto-generated
|
||||
// Code generated by '$ fyne bundle'. DO NOT EDIT.
|
||||
|
||||
package main
|
||||
|
||||
import "fyne.io/fyne/v2"
|
||||
|
||||
var resourcePiloadingGif = &fyne.StaticResource{
|
||||
StaticName: "piloading.gif",
|
||||
StaticContent: []byte(
|
||||
"GIF87a@\x01@\x01w\x00\x00!\xff\vNETSCAPE2.0\x03\x01\x00\x00\x00!\xf9\x04\t2\x00\x00\x00,\x00\x00\x00\x00@\x01@\x01\x80\x00\x00\x00\" 4\x02\xff\x84\x8f\xa9\xcb\xed\x0f\xa3\x9c\xb4ڋ\xb3\u07bc\xfb\x0f\x86\xe2H\x96扦\xeaʶ\xee\v\xc7\xf2L\xd7\xf6\x8d\xe7\xfa\xce\xf7\xfe\x0f\f\n\x87Ģ\xf1\x88L*\x97̦\xf3\t\x8dJ\xa7Ԫ\xf5\x8a\xcdj\xb7ܮ\xf7\v\x0e\x8b\xc7\xe4\xb2\xf9\x8cN\xab\xd7\xec\xb6\xfb\r\x8f\xcb\xe7\xf4\xba\xfd\x8e\xcf\xeb\xf7\xfc\xbe\xff\x0f\x18(8HXhx\x88\x98\xa8\xb8\xc8\xd8\xe8\xf8\b\x19)9IYiy\x89\x99\xa9\xb9\xc9\xd9\xe9\xf9\t\x1a*:JZjz\x8a\x9a\xaa\xba\xca\xda\xea\xfa\n\x1b+;K[k{\x8b\x9b\xab\xbb\xcb\xdb\xeb\xfb\v\x1c,<L\\l|\x8c\x9c\xac\xbc\xcc\xdc\xec\xfc\f\x1d-=M]m}\x8d\x9d\xad\xbd\xcd\xdd\xed\xfd\r\x1e.>N^n~\x8e\x9e\xae\xbe\xce\xde\xee\xfe\x0e\x1f/?\xcf\x1c`\x7f\x8f\x9f\xaf\xbf\xcf\xdf\xef\xff\x0f\xd0\x1e\xbd\x80\x04\v\x1a<\x98o \u0085\f\x1b\x06P\xe80\xa2\xc4~\x10'Z\xb4X\xf1\xa2Ɔ\xff\x197z4\xd8\xf1\xa3\xc8\x7f!G\x9a\xd4W\xf2\xa4ʇ\xf3\xfc\x01qْ\xe2\x0f\x98\xf2h\xf6\xb0\t\x0f\xe7\x0e\x9d\xeex\xe6\xf0\xc9\x0e\xe8\r\xa1\xea\x88\xd60\x8a\x0e\xe9\f\xa5\xe6\x98\xc6pJ\x0e\xea\v\xa9⨶\xb0\xea\x00\xeb-\xad*\xb8.\xf0J\v\xec\t\xb1\b\xc8\xc62K\x02-\x00\xb5\xae؆P\xeb\x96U\xdc\x0fpe*\x9b\xeb\xa1.\xbfzvo\xf6\xcd\xfb\xf7\x18\xde\x0ez\xf7\xf1\xdd;30\x87\xc1\xa8\x18op\xec\fr\x06ɇ\r'F\\S\xf1O\xcdA9\x0f\xf5\\\x14\xf4Q\xd1II/5\xdd\x14\xf5S\xd5QYOu]\x15\xf6U\xd9\xe0(_\xb0}\x97\xf6\n\xdc\xc9xS\xf0-XwW\xe1݀K0^\f9\x04\xe5Øg%\xce\xcdy\x03\xe9\xc0\xa8\x7f\x85\xbeͺ\x02\xed\xbd\xb8\x97\xc5\xfe\x1dso\xf0%\n\xa3\\\xe6\xfd\x80\xf9\x84\xe8ɧu\xbf\x16~[\xf9o᧗t?\xbex\xc0\xfb\x83\xf7\xffױ\x1e>\x95\x9d\xe7C\x80\xf7\f\xc8^\x81\xf6\xd1'\x17\x83t-\xf8_r+M(`}\x11\x12Ca\x86,\x81\x90\x1f$\x1aR(B\x87\x8f|8a\x88\x0e\xaaB\xe2J&^\xd8\\\x8a'\xadhYn.\x8e\x04#\x81\xe3\xcd(R\x8d\tވ\xa3G:V(c\x8f\x1b\xfdx`{,z!\xa2#I\xa6\xb0$#M\x8eub*O\x9a0e\"U\xbewd0W\x8e\xb0\xa5!]Z\x18#\x8f6\x92\xf1%!e>\x98euQ\x12q\xa6 m\x12\xb6\xe6)o.\x16\xa7)s>Vg)wj\xb0g\x1f}b\xf0\xe7\x1e\x81Z0h\x1e\x85\xfe\x96')\x87N\xb0\xa8\x1d\x8dF\xf0(\x1d\x91>0\xa9\x1c\x95N\x97\xe8(\x972\xb0\xe9\x1b\x9dn\x97\xa9(\x9f&0*\x1b\xa5\xaa\x17j(\xa7\x1a\xb0j\x1a\xad\xb6\x8aƫ\xa9\x82\"k\x9a\xbf\xd4\x1a&2\xb8\x8e\xe9_\xaec\xc0zƮ;\xea:\xebN\xc5z\",\x90b\xff\x0e\xfb뱝$[d\x90\xbc\x8a\x01\xac\x19\xd0\nd\xa4\xaf\xd4:\xcbɵ\x1b.\xab,\x99\xdcn\xe2-\x82\xe16k\xab/\xe5f;m\x18Ֆ\xb1\xae\xb4\xccn\x9bnw\xe3\xda\xf0\xae\xb8\xf5b\x91/\xbaں{o&\xf1\x82\x1b-\xbc\x01c20\xb1\xfb^\xd1/\xbd\xff\x82\xd10\xc0\v[\x111\xc4\a\x9f6q.\t\xf7ڮ\xc5\x19㲱1!K\xf8\xf1\x14\x15\x7f12\x86\x17\xcbp2\x92+\xafV\xb2-)\xb7\x18s\x14-w1\xb309k\xf92\f7s\xb1\xb3\x9a5C\xf1\xf3\x16A\xdf\xda\xf3kC\xcfr\xb4\xbaI\xbbP\xb4\x16Mۻ\xb4\x13Qg15/Yﲵ.]k\xfc\xf4lU\x9f\x156\vW\xf3[\xf6ni+\xb96\x93m;\xf96\x94c\xc3\xf25\xc8qSy\xf7\x1f>✷\x1f{\x03ݷ\x9fC\xf2=\xb7\x9e\x83\x03^\xb8\xa2\x87\x1b\x1d8\x1f\x7f3\x9e\xb8\xa6\x8bKݸ\xa0\x93gc]\xb9\x1e\x8fS\x1e\xb9\xa8\x97\xa3\xdd9=\xa2\x8fNz馟\x8ezꪯ\xcez뮿\x0e{\xec\xb2\xcfN{\xed\xb6ߎ{\xee\xba\xef\xce{\xef\xbe\xff\x0e|\xf0\xc2\x0fO|\xf1\xc6\x1f\x8f|\xf2\xca/\xcf|\xf3\xce?\x0f}\xf4\xd2OO}\xf5\xd6_\x8f}\xf6\xdao\xcf}\xf7\xde\x7f\x0f~\xf8\xe2\x8fO~\xf9\xe63Q\x00\x00!\xf9\x04\t\n\x00\x00\x00,2\x00P\x00\xb4\x00\xb4\x00\x80\x00\x00\x00\" 4\x02\xff\x84\x8f\xa9\xcb\xed\x19\xa2\x9c\xb4\xda;\x9f\u07bc\xfb\x0f\x86\x10F\x96\x98\x88\xa6\xeaʎ\xe6\xfb\xb6\xf2L\xd7\xf0]\xd6\xfa\xces\xf8o\xe9\t\x87B\xa0QBL*[\xc7\xe3\xf2\t\xfd4\x8dѪ\x951\x05^\xb7\xdb\xec\x8f\v摖\xdeJ8<V\x96)gp:\xb9δ\xbb'u<2\xa7_\xc8\xf7@\xfe\xfaF\xd4\xe7\xf7W\x1584XhX\aק\x18uX\xe4\xf8\xf8\x14ٓHɷGi\x99)ƨ\xd8\xe9\xa9#zV::s\xea\x06\x8a\xfa\xb9\xf9\xa8ں\x12\xab\x17${\xc9\xfaG{+\xb2k\xe5\xcb+\x95\x9b\a\x1c\xdcQ\f\x85l\xac\xa1\xaci\xbb\x9c:<\xd7\f\x8d%\xddF]\xad\x90-x\xad\r\u008d\xe8\xfd\xed\x11.\xf9J\x9eb\x8e\x8b\x9e\xde;\xbe\xda\xee\x0e\x0eϵ\xae}\xbf\x93\x0f\xbd\xff.?[/T@q\xffT\xf4\xb3S0\xd9\xc0c\v\x895t\xf5L\xc6\xc1F\t+=dv\xd1TF\x1b\xff\x1b\x1bL\xecVљ\x19\x1a\x1f\tF\x04\xd4\xd1ZHN)%\xb6\xdc\xf6\xf2WL\x80+\xe9լ\x85\x03\xcdL|T❜'L\x8bϑ@C8\x19ʦ\xa8ў\xf6vV;\xda\xf4\xa6R\x17_\x90ʙZ\x8e)ΤX\x19\n\x8d\xfa\xb3\xab\x03\xa8[\xaf\x8a\xc58(mճhպ5\xc1v\xc3۹9\xe2>\xa0\x8b7\xac]\x04y\xfb\"\xd9\xeb\xd1o_\xc0\x81\x05\xe3%\xac\xd2\xf0\\\xc4\v\x14\x1ffLձZȑ\xb9\x96\xfdKQ/6\xa7(JV6[ȳ\x0f\xcecI\x934mS3)\xd4.\xa5\x9eS\xcd\xd1\xf5\"\xd9\x10\x89\x82\x84m\x15\xf3e<\bq\x83\xb5\x8d\x92\xb6:\xd6L\x88{\xf5\xdd\x1ayp寁7\xb7\xbc\xdc9c\xd1\x06\x8d\xb7\xa2>\\\xb8R읭\xa3\xe2\xee\x8fyW\xf0K\xb5\x17%\x9fZ:b\xf4A\xc5ce\x9f\xd5<P\xf8\xc7\xd5\x13\xa6?Z\xfe<\xfcr\xbd\x8f\xff\xe2ߖ}\x80\x01x\x97\x7f\x9e\x10X\x9a~\xee X\x98{S1\x98\x98\x80{Aؘ\x81\x99P\b\x93\x82\xe9`\xf8\x99n\x94qȗ\x85,i\xf8\x1ch\x90\x81x\x00\x8a\n\x91Ȏ\x83ۉ\x98\x1et'\xc2؞\x84v\xa9\b\x00\x8e\"\xc9\xe8\x10\x8b<\xf9\xa8\x0f\x8d\xa1\tY\x1f\x8f\xeb\x11\x99\x9f\x8b\xe7!\xd9\x1f\x90\xfc0\x19\xa0\x91\xf7AY\xa0\x93\xcb\xe0\xa8co6\xfe&\xe5\x80T&\xa8\xe4|_6\xb8%[X\x8eɥ\x89=\x86\xb9\x1f\x95YfVft]N\x88f\x85V\x1as\xe6\x9d\xc1\xe4\xc9\xe6\x82uf\xd8\xe7\x86\x7fv\xc8\x1be\x06\xf0\x19\xa7X\x88\xcey\xe3\xa0!\xea\xc9ˢjLine truncated
|
||||
}
|
||||
Reference in new issue
Block a user