Init
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.vscode
|
BIN
blackchancery.zip
Normal file
91
conf/config.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"fornaxian.com/pixeldrain-web/log"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var vi *viper.Viper
|
||||
|
||||
var defaultConfig = `# Pixeldrain Web UI server configuration
|
||||
api_url = "http://127.0.0.1:8080/api"
|
||||
static_resource_dir = "res/static"
|
||||
template_dir = "res/template"
|
||||
debug_mode = false`
|
||||
|
||||
// Init reads the config file
|
||||
func Init() {
|
||||
if vi != nil {
|
||||
log.Error("Config already initialized, can't ititialize again")
|
||||
return
|
||||
}
|
||||
|
||||
vi = viper.New()
|
||||
vi.SetConfigType("toml")
|
||||
vi.SetConfigName("pdwebconf")
|
||||
|
||||
vi.AddConfigPath(".")
|
||||
vi.AddConfigPath("./conf")
|
||||
vi.AddConfigPath("/etc")
|
||||
vi.AddConfigPath("/usr/local/etc")
|
||||
|
||||
vi.SetDefault("api_url", "http://127.0.0.1:8080/api")
|
||||
vi.SetDefault("static_resource_dir", "./res/static")
|
||||
vi.SetDefault("template_dir", "./res/template")
|
||||
vi.SetDefault("debug_mode", false)
|
||||
|
||||
err := vi.ReadInConfig()
|
||||
|
||||
if err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
writeCfg()
|
||||
log.Warn("Generated config file \"pdapiconf.toml\", please edit and run again.")
|
||||
os.Exit(0)
|
||||
} else if _, ok := err.(viper.ConfigParseError); ok {
|
||||
log.Error("Could not parse config file: ", err)
|
||||
} else {
|
||||
log.Error("Unknown error occured while reading config file: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Web UI configuration:")
|
||||
keys := vi.AllKeys()
|
||||
numKeys := len(keys)
|
||||
sort.Strings(keys)
|
||||
for i, v := range keys {
|
||||
if i == numKeys-1 {
|
||||
log.Info("└%21s: %v", v, vi.Get(v))
|
||||
} else {
|
||||
log.Info("├%21s: %v", v, vi.Get(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeCfg() {
|
||||
file, err := os.Create("pdwebconf.toml")
|
||||
|
||||
if err != nil {
|
||||
log.Error("Could not create config file: ", err)
|
||||
}
|
||||
|
||||
file.WriteString(defaultConfig)
|
||||
|
||||
file.Close()
|
||||
}
|
||||
|
||||
// ApiURL returns the API URL
|
||||
func ApiURL() string {
|
||||
return vi.GetString("api_url")
|
||||
}
|
||||
func StaticResourceDir() string {
|
||||
return vi.GetString("static_resource_dir")
|
||||
}
|
||||
func TemplateDir() string {
|
||||
return vi.GetString("template_dir")
|
||||
}
|
||||
func DebugMode() bool {
|
||||
return vi.GetBool("debug_mode")
|
||||
}
|
34
init/init.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"fornaxian.com/pixeldrain-web/conf"
|
||||
"fornaxian.com/pixeldrain-web/log"
|
||||
"fornaxian.com/pixeldrain-web/webcontroller"
|
||||
"fornaxian.com/pixeldrain-web/webcontroller/templates"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
// Init initializes the Pixeldrain Web UI controllers
|
||||
func Init(r *httprouter.Router, prefix string) {
|
||||
log.Init()
|
||||
log.Info("Starting web UI server (PID %v)", os.Getpid())
|
||||
conf.Init()
|
||||
|
||||
templates.ParseTemplates()
|
||||
|
||||
// Serve static files
|
||||
r.ServeFiles(prefix+"/res/*filepath", http.Dir(conf.StaticResourceDir()+"/res"))
|
||||
|
||||
r.GET(prefix+"/", webcontroller.ServeHome)
|
||||
r.GET(prefix+"/favicon.ico", webcontroller.ServeFavicon)
|
||||
r.GET(prefix+"/api", webcontroller.ServeAPIDoc)
|
||||
r.GET(prefix+"/history", webcontroller.ServeHistory)
|
||||
r.GET(prefix+"/u/:id", webcontroller.ServeFileViewer)
|
||||
r.GET(prefix+"/u/:id/preview", webcontroller.ServeFilePreview)
|
||||
r.GET(prefix+"/t", webcontroller.ServePaste)
|
||||
|
||||
r.NotFound = http.HandlerFunc(webcontroller.ServeNotFound)
|
||||
}
|
97
log/log.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var logger *log.Logger
|
||||
|
||||
const (
|
||||
LEVEL_DEBUG = 4
|
||||
LEVEL_INFO = 3
|
||||
LEVEL_WARNING = 2
|
||||
LEVEL_ERROR = 1
|
||||
)
|
||||
|
||||
var logLevel = LEVEL_DEBUG
|
||||
|
||||
// Init initializes the logger
|
||||
func Init() {
|
||||
logger = log.New(os.Stdout, "pdweb ", log.LUTC)
|
||||
}
|
||||
|
||||
// SetLogLevel set the loggin verbosity. 0 is lowest (log nothing at all), 4 is
|
||||
// highest (log all debug messages)
|
||||
func SetLogLevel(level int) {
|
||||
if level < 0 || level > 4 {
|
||||
Error("Invalid log level %v", level)
|
||||
return
|
||||
}
|
||||
logLevel = level
|
||||
}
|
||||
|
||||
// Debug logs a debug message
|
||||
func Debug(msgFmt string, v ...interface{}) {
|
||||
if logLevel < LEVEL_DEBUG {
|
||||
return
|
||||
}
|
||||
if len(v) == 0 {
|
||||
print("DBG", msgFmt)
|
||||
} else {
|
||||
print("DBG", msgFmt, v...)
|
||||
}
|
||||
}
|
||||
|
||||
// Info logs an info message
|
||||
func Info(msgFmt string, v ...interface{}) {
|
||||
if logLevel < LEVEL_INFO {
|
||||
return
|
||||
}
|
||||
if len(v) == 0 {
|
||||
print("INF", msgFmt)
|
||||
} else {
|
||||
print("INF", msgFmt, v...)
|
||||
}
|
||||
}
|
||||
|
||||
// Warn logs a warning message
|
||||
func Warn(msgFmt string, v ...interface{}) {
|
||||
if logLevel < LEVEL_WARNING {
|
||||
return
|
||||
}
|
||||
if len(v) == 0 {
|
||||
print("WRN", msgFmt)
|
||||
} else {
|
||||
print("WRN", msgFmt, v...)
|
||||
}
|
||||
}
|
||||
|
||||
// Error logs an error message
|
||||
func Error(msgFmt string, v ...interface{}) {
|
||||
if logLevel < LEVEL_ERROR {
|
||||
return
|
||||
}
|
||||
if len(v) == 0 {
|
||||
print("ERR", msgFmt)
|
||||
} else {
|
||||
print("ERR", msgFmt, v...)
|
||||
}
|
||||
|
||||
debug.PrintStack()
|
||||
}
|
||||
|
||||
func print(lvl string, msgFmt string, v ...interface{}) {
|
||||
_, fn, line, _ := runtime.Caller(2)
|
||||
|
||||
msg := fmt.Sprintf("[%s] …%s:%-3d %s", lvl, string(fn[len(fn)-20:]), line, msgFmt)
|
||||
|
||||
if len(v) == 0 {
|
||||
logger.Println(msg)
|
||||
} else {
|
||||
logger.Printf(msg, v...)
|
||||
}
|
||||
}
|
25
main.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
web "fornaxian.com/pixeldrain-web/init"
|
||||
"fornaxian.com/pixeldrain-web/log"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
// This is just a launcher for the web server. During testing the app would
|
||||
// be directly embedded by another Go project. And when deployed it will run
|
||||
// independently.
|
||||
func main() {
|
||||
r := httprouter.New()
|
||||
|
||||
web.Init(r, "")
|
||||
|
||||
err := http.ListenAndServe(":8081", r)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Can't listen and serve Pixeldrain Web: %v", err)
|
||||
}
|
||||
}
|
40
pixelapi/fileInfo.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package pixelapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"fornaxian.com/pixeldrain-web/conf"
|
||||
"fornaxian.com/pixeldrain-web/log"
|
||||
)
|
||||
|
||||
// FileInfo File information object from the pixeldrain API
|
||||
type FileInfo struct {
|
||||
ID string `json:"id"`
|
||||
FileName string `json:"file_name"`
|
||||
DateUpload int64 `json:"date_upload"`
|
||||
DateLastview int64 `json:"date_last_view"`
|
||||
DaysValid uint16 `json:"days_valid"`
|
||||
FileSize uint64 `json:"file_size"`
|
||||
Views uint `json:"views"`
|
||||
MimeType string `json:"mime_type"`
|
||||
Description string `json:"description"`
|
||||
MimeImage string `json:"mime_image"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
}
|
||||
|
||||
// GetFileInfo gets the FileInfo from the pixeldrain API
|
||||
func GetFileInfo(id string) *FileInfo {
|
||||
body, err := get(conf.ApiURL() + "/file/" + id + "/info")
|
||||
|
||||
if err != nil {
|
||||
log.Error("req failed: %v", err)
|
||||
return nil
|
||||
}
|
||||
var fileInfo FileInfo
|
||||
err = json.Unmarshal([]byte(body), &fileInfo)
|
||||
if err != nil {
|
||||
log.Error("unmarshal failed: %v. json: %s", err, body)
|
||||
return nil
|
||||
}
|
||||
return &fileInfo
|
||||
}
|
24
pixelapi/request.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package pixelapi
|
||||
|
||||
import "net/http"
|
||||
import "io/ioutil"
|
||||
|
||||
func get(url string) (string, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
return string(bodyBytes), err
|
||||
}
|
BIN
res/static/favicon.ico
Normal file
After Width: | Height: | Size: 361 KiB |
BIN
res/static/res/img/arrow-down.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/static/res/img/arrow-left.png
Normal file
After Width: | Height: | Size: 732 B |
BIN
res/static/res/img/arrow-right.png
Normal file
After Width: | Height: | Size: 700 B |
BIN
res/static/res/img/arrows-collapse.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
res/static/res/img/arrows-expand.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
res/static/res/img/arrows-slide.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
res/static/res/img/bytecounter.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
res/static/res/img/checker0.png
Normal file
After Width: | Height: | Size: 172 B |
BIN
res/static/res/img/checker1.png
Normal file
After Width: | Height: | Size: 203 B |
BIN
res/static/res/img/checker10.png
Normal file
After Width: | Height: | Size: 251 B |
BIN
res/static/res/img/checker11.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
res/static/res/img/checker12.png
Normal file
After Width: | Height: | Size: 195 B |
BIN
res/static/res/img/checker13.png
Normal file
After Width: | Height: | Size: 314 B |
BIN
res/static/res/img/checker14.png
Normal file
After Width: | Height: | Size: 360 B |
BIN
res/static/res/img/checker15.png
Normal file
After Width: | Height: | Size: 354 B |
BIN
res/static/res/img/checker2.png
Normal file
After Width: | Height: | Size: 215 B |
BIN
res/static/res/img/checker3.png
Normal file
After Width: | Height: | Size: 267 B |
BIN
res/static/res/img/checker4.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
res/static/res/img/checker5.png
Normal file
After Width: | Height: | Size: 280 B |
BIN
res/static/res/img/checker6.png
Normal file
After Width: | Height: | Size: 260 B |
BIN
res/static/res/img/checker7.png
Normal file
After Width: | Height: | Size: 262 B |
BIN
res/static/res/img/checker8.png
Normal file
After Width: | Height: | Size: 266 B |
BIN
res/static/res/img/checker9.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
res/static/res/img/client.png
Normal file
After Width: | Height: | Size: 251 KiB |
BIN
res/static/res/img/clipboard.png
Normal file
After Width: | Height: | Size: 450 B |
1
res/static/res/img/clipboard.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg height="1000" width="707" xmlns="http://www.w3.org/2000/svg"><path d="M0 999.936l0 -904.239l224.595 0l0 64.449l-160.146 0l0 773.388l578.088 0l0 -773.388l-160.146 0l0 -64.449l224.595 0l0 904.239l-706.986 0zm128.898 -128.898l0 -31.248l31.248 0l0 31.248l-31.248 0zm0 -121.086l0 -31.248l31.248 0l0 31.248l-31.248 0zm0 -121.086l0 -31.248l31.248 0l0 31.248l-31.248 0zm0 -121.086l0 -31.248l31.248 0l0 31.248l-31.248 0zm0 -121.086l0 -31.248l31.248 0l0 31.248l-31.248 0zm0 -95.697l0 -93.744l128.898 0l0 -97.65q0 -41.013 27.342 -70.308t68.355 -29.295 69.332 30.271 28.319 69.332q0 56.637 -1.953 97.65l128.898 0l0 93.744l-449.19 0zm95.697 581.994l0 -33.201l353.493 0l0 33.201l-353.493 0zm0 -121.086l0 -33.201l353.493 0l0 33.201l-353.493 0zm0 -121.086l0 -33.201l353.493 0l0 33.201l-353.493 0zm0 -121.086l0 -33.201l353.493 0l0 33.201l-353.493 0zm0 -121.086l0 -33.201l353.493 0l0 33.201l-353.493 0zm97.65 -259.749q0 13.671 8.789 22.46t22.46 8.789 22.46 -8.789 8.789 -22.46 -8.789 -23.436 -22.46 -9.765 -22.46 9.765 -8.789 23.436z"/></svg>
|
After Width: | Height: | Size: 1.0 KiB |
BIN
res/static/res/img/clipboard_small.png
Normal file
After Width: | Height: | Size: 295 B |
BIN
res/static/res/img/cloud-cover-light.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
res/static/res/img/cloud-cover.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
res/static/res/img/cross.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
res/static/res/img/dropTexture.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
res/static/res/img/fade.png
Normal file
After Width: | Height: | Size: 313 B |
BIN
res/static/res/img/floppy.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/static/res/img/floppy_small.png
Normal file
After Width: | Height: | Size: 252 B |
BIN
res/static/res/img/header.png
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
res/static/res/img/header.xcf
Normal file
BIN
res/static/res/img/header_blackchancery.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
res/static/res/img/header_blackchancery.xcf
Normal file
BIN
res/static/res/img/info.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
res/static/res/img/info_small.png
Normal file
After Width: | Height: | Size: 751 B |
BIN
res/static/res/img/mime/application.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
res/static/res/img/mime/archive.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
res/static/res/img/mime/audio.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
res/static/res/img/mime/cross.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
res/static/res/img/mime/database.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
res/static/res/img/mime/drawing.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
res/static/res/img/mime/font.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
res/static/res/img/mime/image-bmp.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
res/static/res/img/mime/image-gif.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
res/static/res/img/mime/image-jpeg.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
res/static/res/img/mime/image-png.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
res/static/res/img/mime/image-tiff.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
res/static/res/img/mime/java.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
res/static/res/img/mime/mail.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
res/static/res/img/mime/ms-excel.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
res/static/res/img/mime/ms-onenote.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
res/static/res/img/mime/ms-outlook.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
res/static/res/img/mime/ms-powerpoint.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
res/static/res/img/mime/ms-publisher.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
res/static/res/img/mime/ms-word.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
res/static/res/img/mime/multimedia.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 120 KiB |
BIN
res/static/res/img/mime/pdf.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
res/static/res/img/mime/photo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
res/static/res/img/mime/presentation.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
res/static/res/img/mime/python.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
res/static/res/img/mime/ruby.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
res/static/res/img/mime/spreadsheet.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
res/static/res/img/mime/terminal.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
res/static/res/img/mime/text.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
res/static/res/img/mime/textdocument.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
res/static/res/img/mime/video.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
res/static/res/img/misc/drives.jpg
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
res/static/res/img/misc/hair-on-fire.jpg
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
res/static/res/img/pixeldrain.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
res/static/res/img/pixeldrain_big.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
res/static/res/img/pixeldrain_logo.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
res/static/res/img/pixeldrain_logo.xcf
Normal file
BIN
res/static/res/img/pixeldrain_small.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
res/static/res/img/pixeldrain_transparent.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
res/static/res/img/pixeldrain_transparent.xcf
Normal file
BIN
res/static/res/img/share.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
res/static/res/img/share_small.png
Normal file
After Width: | Height: | Size: 770 B |
BIN
res/static/res/img/shuffle_small.png
Normal file
After Width: | Height: | Size: 523 B |
1
res/static/res/img/sia-droplet.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="m1199.04 333.29c-48.944-30.755-110.28-33.911-161.84-9.63-.027-.04-.053-.071-.08-.111-27.383 12.349-60.32 7.977-83.73-13-1.062-.947-2.102-1.902-3.128-2.928l-103.86-103.86c-.009-.009-.102-.053-.084-.084-6.955-7.786-9.843-17.784-8.754-27.525-.022-.018-.062-.013-.08-.022.395-2.137.622-4.324.627-6.581-.004-19.628-15.922-35.541-35.555-35.541-19.633 0-35.55 15.918-35.55 35.55 0 19.624 15.913 35.55 35.546 35.55 2.253 0 4.448-.236 6.586-.635.009.027.022.044.031.067 9.745-1.089 19.948 1.609 27.725 8.563.036-.018.076.076.084.084l104.35 104.35c.853.853 1.551 1.831 2.351 2.724 20.997 23.419 25.285 56.45 12.905 83.84.036.027.044.062.08.089-24.29 51.561-21.15 112.92 9.612 161.86 6.59 10.514 14.411 20.459 23.543 29.6 29.11 29.11 67.75 46.34 105.86 49.726 9.981.871 152.22.387 152.22.387 7.71 0 15.633-3.822 21.09-9.27 5.453-5.448 10.02-14.12 10.02-21.837 0 0-.009-130.88 0-137.76.018-6.875-1.48-16.749-1.604-18.16-3.377-38.11-19.619-72.79-48.731-101.9-9.136-9.128-19.12-16.953-29.627-23.548m9.114 115.33c3.999 19.646 4.19 28.28 4.19 29.596v69.781c0 7.723-3.435 16.766-8.888 22.22-5.453 5.453-14.505 8.888-22.22 8.888h-67.786c-1.306 0-17.22-.187-31.849-4.222-16.375-4.515-31.804-13.38-44.651-26.23-39.856-39.843-39.852-104.79-.004-144.64 39.856-39.847 104.98-39.874 144.83-.027 12.847 12.843 22.983 27.996 26.378 44.633" transform="translate(-767-134)" fill-opacity=".355" fill="#111113"/></g></svg>
|
After Width: | Height: | Size: 1.5 KiB |
BIN
res/static/res/img/sia.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
res/static/res/img/social_email.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
res/static/res/img/social_facebook.png
Normal file
After Width: | Height: | Size: 556 B |
BIN
res/static/res/img/social_googleplus.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
res/static/res/img/social_reddit.png
Normal file
After Width: | Height: | Size: 912 B |