Compare commits
6 Commits
master
...
RELEASE.20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c59a41668 | ||
|
|
29a2ffef5d | ||
|
|
c836c454cc | ||
|
|
0f7300058b | ||
|
|
c5300ec279 | ||
|
|
3d8d12ba1b |
@@ -1,19 +1,17 @@
|
||||
FROM golang:1.6-alpine
|
||||
FROM golang:1.7-alpine
|
||||
|
||||
WORKDIR /go/src/app
|
||||
ENV ALLOW_CONTAINER_ROOT=1
|
||||
|
||||
COPY . /go/src/app
|
||||
RUN \
|
||||
apk add --no-cache git && \
|
||||
go-wrapper download && \
|
||||
go-wrapper install && \
|
||||
go-wrapper install -ldflags "-X github.com/minio/minio/cmd.Version=2016-10-07T01:16:39Z -X github.com/minio/minio/cmd.ReleaseTag=RELEASE.2016-10-07T01-16-39Z -X github.com/minio/minio/cmd.CommitID=b06a514ce0cf10f1d4c8bbc7b5cdbd956c567ab9" && \
|
||||
mkdir -p /export/docker && \
|
||||
cp /go/src/app/docs/Docker.md /export/docker/ && \
|
||||
rm -rf /go/pkg /go/src && \
|
||||
apk del git
|
||||
|
||||
EXPOSE 9000
|
||||
ENTRYPOINT ["go-wrapper", "run", "server"]
|
||||
ENTRYPOINT ["go-wrapper", "run"]
|
||||
VOLUME ["/export"]
|
||||
CMD ["/export"]
|
||||
|
||||
131
README.md
131
README.md
@@ -1,9 +1,8 @@
|
||||
# Minio Quickstart Guide [](https://gitter.im/minio/minio?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://goreportcard.com/report/minio/minio) [](https://codecov.io/gh/minio/minio)
|
||||
# Minio Quickstart Guide [](https://gitter.im/minio/minio?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://goreportcard.com/report/minio/minio) [](https://hub.docker.com/r/minio/minio/) [](https://codecov.io/gh/minio/minio)
|
||||
|
||||
Minio is an object storage server released under Apache License v2.0. It is compatible with Amazon S3 cloud storage service. It is best suited for storing unstructured data such as photos, videos, log files, backups and container / VM images. Size of an object can range from a few KBs to a maximum of 5TB.
|
||||
|
||||
## 1. Download
|
||||
|
||||
Minio server is light enough to be bundled with the application stack, similar to NodeJS, Redis and MySQL.
|
||||
|
||||
| Platform| Architecture | URL|
|
||||
@@ -17,7 +16,6 @@ Minio server is light enough to be bundled with the application stack, similar t
|
||||
|FreeBSD|64-bit|https://dl.minio.io/server/minio/release/freebsd-amd64/minio|
|
||||
|
||||
### Install from Homebrew
|
||||
|
||||
Install minio packages using [Homebrew](http://brew.sh/)
|
||||
|
||||
```sh
|
||||
@@ -26,169 +24,79 @@ $ minio --help
|
||||
```
|
||||
|
||||
### Install from Source
|
||||
|
||||
Source installation is only intended for developers and advanced users. If you do not have a working Golang environment, please follow [How to install Golang](https://docs.minio.io/docs/how-to-install-golang).
|
||||
|
||||
|
||||
```sh
|
||||
|
||||
$ go get -u github.com/minio/minio
|
||||
|
||||
|
||||
```
|
||||
|
||||
## 2. Run Minio Server
|
||||
In the examples below, Minio serves the contents of the ``Photos`` directory as an object store.
|
||||
|
||||
### Docker Container
|
||||
|
||||
```sh
|
||||
$ docker pull minio/minio
|
||||
$ docker run -p 9000:9000 minio/minio server /export
|
||||
```
|
||||
|
||||
Please visit Minio Docker quickstart guide for more [here](https://docs.minio.io/docs/minio-docker-quickstart-guide)
|
||||
|
||||
### GNU/Linux
|
||||
|
||||
```sh
|
||||
|
||||
```sh
|
||||
$ chmod +x minio
|
||||
$ ./minio --help
|
||||
$ ./minio server ~/Photos
|
||||
|
||||
Endpoint: http://10.0.0.10:9000 http://127.0.0.1:9000 http://172.17.0.1:9000
|
||||
AccessKey: USWUXHGYZQYFYFFIT3RE
|
||||
SecretKey: MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
Region: us-east-1
|
||||
|
||||
Browser Access:
|
||||
http://10.0.0.10:9000 http://127.0.0.1:9000 http://172.17.0.1:9000
|
||||
|
||||
Command-line Access: https://docs.minio.io/docs/minio-client-quickstart-guide
|
||||
$ mc config host add myminio http://10.0.0.10:9000 USWUXHGYZQYFYFFIT3RE MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
|
||||
Object API (Amazon S3 compatible):
|
||||
Go: https://docs.minio.io/docs/golang-client-quickstart-guide
|
||||
Java: https://docs.minio.io/docs/java-client-quickstart-guide
|
||||
Python: https://docs.minio.io/docs/python-client-quickstart-guide
|
||||
JavaScript: https://docs.minio.io/docs/javascript-client-quickstart-guide
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
### OS X
|
||||
|
||||
|
||||
```sh
|
||||
|
||||
```sh
|
||||
$ chmod 755 minio
|
||||
$ ./minio --help
|
||||
$ ./minio server ~/Photos
|
||||
|
||||
Endpoint: http://10.0.0.10:9000 http://127.0.0.1:9000 http://172.17.0.1:9000
|
||||
AccessKey: USWUXHGYZQYFYFFIT3RE
|
||||
SecretKey: MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
Region: us-east-1
|
||||
|
||||
Browser Access:
|
||||
http://10.0.0.10:9000 http://127.0.0.1:9000 http://172.17.0.1:9000
|
||||
|
||||
Command-line Access: https://docs.minio.io/docs/minio-client-quickstart-guide
|
||||
$ mc config host add myminio http://10.0.0.10:9000 USWUXHGYZQYFYFFIT3RE MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
|
||||
Object API (Amazon S3 compatible):
|
||||
Go: https://docs.minio.io/docs/golang-client-quickstart-guide
|
||||
Java: https://docs.minio.io/docs/java-client-quickstart-guide
|
||||
Python: https://docs.minio.io/docs/python-client-quickstart-guide
|
||||
JavaScript: https://docs.minio.io/docs/javascript-client-quickstart-guide
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
### Microsoft Windows
|
||||
|
||||
```sh
|
||||
|
||||
C:\Users\Username\Downloads> minio.exe --help
|
||||
C:\Users\Username\Downloads> minio.exe server D:\Photos
|
||||
|
||||
Endpoint: http://10.0.0.10:9000 http://127.0.0.1:9000 http://172.17.0.1:9000
|
||||
AccessKey: USWUXHGYZQYFYFFIT3RE
|
||||
SecretKey: MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
Region: us-east-1
|
||||
|
||||
Browser Access:
|
||||
http://10.0.0.10:9000 http://127.0.0.1:9000 http://172.17.0.1:9000
|
||||
|
||||
Command-line Access: https://docs.minio.io/docs/minio-client-quickstart-guide
|
||||
$ mc.exe config host add myminio http://10.0.0.10:9000 USWUXHGYZQYFYFFIT3RE MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
|
||||
Object API (Amazon S3 compatible):
|
||||
Go: https://docs.minio.io/docs/golang-client-quickstart-guide
|
||||
Java: https://docs.minio.io/docs/java-client-quickstart-guide
|
||||
Python: https://docs.minio.io/docs/python-client-quickstart-guide
|
||||
JavaScript: https://docs.minio.io/docs/javascript-client-quickstart-guide
|
||||
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
### Docker Container
|
||||
|
||||
```sh
|
||||
|
||||
$ docker pull minio/minio
|
||||
$ docker run -p 9000:9000 minio/minio
|
||||
|
||||
```
|
||||
Please visit Minio Docker quickstart guide for more [here](https://docs.minio.io/docs/minio-docker-quickstart-guide)
|
||||
|
||||
### FreeBSD
|
||||
|
||||
```sh
|
||||
|
||||
$ chmod 755 minio
|
||||
$ ./minio --help
|
||||
$ ./minio server ~/Photos
|
||||
|
||||
Endpoint: http://10.0.0.10:9000 http://127.0.0.1:9000 http://172.17.0.1:9000
|
||||
AccessKey: USWUXHGYZQYFYFFIT3RE
|
||||
SecretKey: MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
Region: us-east-1
|
||||
|
||||
Browser Access:
|
||||
http://10.0.0.10:9000 http://127.0.0.1:9000 http://172.17.0.1:9000
|
||||
|
||||
Command-line Access: https://docs.minio.io/docs/minio-client-quickstart-guide
|
||||
$ mc config host add myminio http://10.0.0.10:9000 USWUXHGYZQYFYFFIT3RE MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
|
||||
Object API (Amazon S3 compatible):
|
||||
Go: https://docs.minio.io/docs/golang-client-quickstart-guide
|
||||
Java: https://docs.minio.io/docs/java-client-quickstart-guide
|
||||
Python: https://docs.minio.io/docs/python-client-quickstart-guide
|
||||
JavaScript: https://docs.minio.io/docs/javascript-client-quickstart-guide
|
||||
|
||||
|
||||
...
|
||||
```
|
||||
Please visit official zfs FreeBSD guide for more details [here](https://www.freebsd.org/doc/handbook/zfs-quickstart.html)
|
||||
|
||||
## 3. Test Minio Server using Minio Browser
|
||||
|
||||
Open a web browser and navigate to http://127.0.0.1:9000 to view your buckets on minio server.
|
||||
|
||||

|
||||
|
||||
|
||||
## 4. Test Minio Server using `mc`
|
||||
|
||||
|
||||
Install mc from [here](https://docs.minio.io/docs/minio-client-quickstart-guide). Use `mc ls` command to list all the buckets on your minio server.
|
||||
|
||||
```sh
|
||||
|
||||
$ mc config host add myminio http://10.0.0.10:9000 USWUXHGYZQYFYFFIT3RE MOJRH0mkL1IPauahWITSVvyDrQbEEIwljvmxdq03
|
||||
$ mc mb myminio/mybucket
|
||||
$ mc ls myminio/
|
||||
[2015-08-05 08:13:22 IST] 0B andoria/
|
||||
[2015-08-05 06:14:26 IST] 0B deflector/
|
||||
[2015-08-05 08:13:11 IST] 0B ferenginar/
|
||||
[2016-03-08 14:56:35 IST] 0B jarjarbing/
|
||||
[2016-01-20 16:07:41 IST] 0B my.minio.io/
|
||||
|
||||
[2015-08-05 08:13:11 IST] 0B mybucket/
|
||||
```
|
||||
|
||||
For more examples please navigate to [Minio Client Complete Guide](https://docs.minio.io/docs/minio-client-complete-guide).
|
||||
|
||||
|
||||
## 5. Explore Further
|
||||
|
||||
- [Minio Erasure Code QuickStart Guide](https://docs.minio.io/docs/minio-erasure-code-quickstart-guide)
|
||||
- [Minio Docker Quickstart Guide](https://docs.minio.io/docs/minio-docker-quickstart-guide)
|
||||
- [Use `mc` with Minio Server](https://docs.minio.io/docs/minio-client-quickstart-guide)
|
||||
@@ -196,6 +104,5 @@ For more examples please navigate to [Minio Client Complete Guide](https://docs.
|
||||
- [Use `s3cmd` with Minio Server](https://docs.minio.io/docs/s3cmd-with-minio)
|
||||
- [Use `minio-go` SDK with Minio Server](https://docs.minio.io/docs/golang-client-quickstart-guide)
|
||||
|
||||
|
||||
## 6. Contribute to Minio Project
|
||||
Please follow Minio [Contributor's Guide](https://github.com/minio/minio/blob/master/CONTRIBUTING.md)
|
||||
|
||||
17
cmd/main.go
17
cmd/main.go
@@ -20,6 +20,8 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/mc/pkg/console"
|
||||
@@ -165,14 +167,17 @@ func Main() {
|
||||
|
||||
// Do not print update messages, if quiet flag is set.
|
||||
if !globalQuiet {
|
||||
// Do not print any errors in release update function.
|
||||
noError := true
|
||||
updateMsg := getReleaseUpdate(minioUpdateStableURL, noError)
|
||||
if updateMsg.Update {
|
||||
console.Println(updateMsg)
|
||||
if strings.HasPrefix(ReleaseTag, "RELEASE.") && c.Args().Get(0) != "update" {
|
||||
updateMsg, _, err := getReleaseUpdate(minioUpdateStableURL, time.Second*1)
|
||||
if err != nil {
|
||||
// Ignore all network related errors.
|
||||
return nil
|
||||
}
|
||||
if updateMsg.Update {
|
||||
console.Println(updateMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -354,7 +354,7 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, validateRegion bo
|
||||
for _, h := range signV4Values.SignedHeaders {
|
||||
if h == "content-length" {
|
||||
header = cloneHeader(req.Header)
|
||||
header.Add("content-length", strconv.FormatInt(r.ContentLength, 10))
|
||||
header.Set("content-length", strconv.FormatInt(r.ContentLength, 10))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -33,10 +36,6 @@ import (
|
||||
// command specific flags.
|
||||
var (
|
||||
updateFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "help, h",
|
||||
Usage: "Help for update.",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "experimental, E",
|
||||
Usage: "Check experimental update.",
|
||||
@@ -49,7 +48,7 @@ var updateCmd = cli.Command{
|
||||
Name: "update",
|
||||
Usage: "Check for a new software update.",
|
||||
Action: mainUpdate,
|
||||
Flags: updateFlags,
|
||||
Flags: append(updateFlags, globalFlags...),
|
||||
CustomHelpTemplate: `Name:
|
||||
minio {{.Name}} - {{.Usage}}
|
||||
|
||||
@@ -114,7 +113,8 @@ func parseReleaseData(data string) (time.Time, error) {
|
||||
if releaseDateSplits[0] != "minio" {
|
||||
return time.Time{}, (errors.New("Update data malformed, missing minio tag"))
|
||||
}
|
||||
// "OFFICIAL" tag is still kept for backward compatibility, we should remove this for the next release.
|
||||
// "OFFICIAL" tag is still kept for backward compatibility.
|
||||
// We should remove this for the next release.
|
||||
if releaseDateSplits[1] != "RELEASE" && releaseDateSplits[1] != "OFFICIAL" {
|
||||
return time.Time{}, (errors.New("Update data malformed, missing RELEASE tag"))
|
||||
}
|
||||
@@ -132,8 +132,28 @@ func parseReleaseData(data string) (time.Time, error) {
|
||||
return parsedDate, nil
|
||||
}
|
||||
|
||||
// User Agent should always following the below style.
|
||||
// Please open an issue to discuss any new changes here.
|
||||
//
|
||||
// Minio (OS; ARCH) APP/VER APP/VER
|
||||
var (
|
||||
userAgentSuffix = "Minio/" + Version + " " + "Minio/" + ReleaseTag + " " + "Minio/" + CommitID
|
||||
userAgentPrefix = "Minio (" + runtime.GOOS + "; " + runtime.GOARCH + ") "
|
||||
userAgent = userAgentPrefix + userAgentSuffix
|
||||
)
|
||||
|
||||
// Check if the operating system is a docker container.
|
||||
func isDocker() bool {
|
||||
cgroup, err := ioutil.ReadFile("/proc/self/cgroup")
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
fatalIf(err, "Unable to read `cgroup` file.")
|
||||
return bytes.Contains(cgroup, []byte("docker"))
|
||||
}
|
||||
|
||||
// verify updates for releases.
|
||||
func getReleaseUpdate(updateURL string, noError bool) updateMessage {
|
||||
func getReleaseUpdate(updateURL string, duration time.Duration) (updateMsg updateMessage, errMsg string, err error) {
|
||||
// Construct a new update url.
|
||||
newUpdateURLPrefix := updateURL + "/" + runtime.GOOS + "-" + runtime.GOARCH
|
||||
newUpdateURL := newUpdateURLPrefix + "/minio.shasum"
|
||||
@@ -143,78 +163,80 @@ func getReleaseUpdate(updateURL string, noError bool) updateMessage {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
// For windows.
|
||||
downloadURL = newUpdateURLPrefix + "/minio.exe?update=yes"
|
||||
downloadURL = newUpdateURLPrefix + "/minio.exe"
|
||||
default:
|
||||
// For all other operating systems.
|
||||
downloadURL = newUpdateURLPrefix + "/minio?update=yes"
|
||||
downloadURL = newUpdateURLPrefix + "/minio"
|
||||
}
|
||||
|
||||
// Initialize update message.
|
||||
updateMsg := updateMessage{
|
||||
updateMsg = updateMessage{
|
||||
Download: downloadURL,
|
||||
Version: Version,
|
||||
}
|
||||
|
||||
// Instantiate a new client with 3 sec timeout.
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
// Fetch new update.
|
||||
data, err := client.Get(newUpdateURL)
|
||||
if err != nil && noError {
|
||||
return updateMsg
|
||||
}
|
||||
fatalIf((err), "Unable to read from update URL ‘"+newUpdateURL+"’.")
|
||||
|
||||
// Error out if 'update' command is issued for development based builds.
|
||||
if Version == "DEVELOPMENT.GOGET" && !noError {
|
||||
fatalIf((errors.New("")),
|
||||
"Update mechanism is not supported for ‘go get’ based binary builds. Please download official releases from https://minio.io/#minio")
|
||||
Timeout: duration,
|
||||
}
|
||||
|
||||
// Parse current minio version into RFC3339.
|
||||
current, err := time.Parse(time.RFC3339, Version)
|
||||
if err != nil && noError {
|
||||
return updateMsg
|
||||
if err != nil {
|
||||
errMsg = "Unable to parse version string as time."
|
||||
return
|
||||
}
|
||||
fatalIf((err), "Unable to parse version string as time.")
|
||||
|
||||
// Verify if current minio version is zero.
|
||||
if current.IsZero() && !noError {
|
||||
fatalIf((errors.New("")),
|
||||
"Updates mechanism is not supported for custom builds. Please download official releases from https://minio.io/#minio")
|
||||
if current.IsZero() {
|
||||
err = errors.New("date should not be zero")
|
||||
errMsg = "Updates mechanism is not supported for custom builds. Please download official releases from https://minio.io/#minio"
|
||||
return
|
||||
}
|
||||
|
||||
// Initialize new request.
|
||||
req, err := http.NewRequest("GET", newUpdateURL, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Set user agent.
|
||||
req.Header.Set("User-Agent", userAgent+" "+fmt.Sprintf("Docker/%t", isDocker()))
|
||||
|
||||
// Fetch new update.
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Verify if we have a valid http response i.e http.StatusOK.
|
||||
if data != nil {
|
||||
if data.StatusCode != http.StatusOK {
|
||||
// Return quickly if noError is set.
|
||||
if noError {
|
||||
return updateMsg
|
||||
}
|
||||
fatalIf((errors.New("")), "Failed to retrieve update notice. "+data.Status)
|
||||
if resp != nil {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
errMsg = "Failed to retrieve update notice."
|
||||
err = errors.New("http status : " + resp.Status)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Read the response body.
|
||||
updateBody, err := ioutil.ReadAll(data.Body)
|
||||
if err != nil && noError {
|
||||
return updateMsg
|
||||
updateBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
errMsg = "Failed to retrieve update notice. Please try again later."
|
||||
return
|
||||
}
|
||||
fatalIf((err), "Failed to retrieve update notice. Please try again later.")
|
||||
|
||||
errMsg = "Failed to retrieve update notice. Please try again later. Please report this issue at https://github.com/minio/minio/issues"
|
||||
|
||||
// Parse the date if its valid.
|
||||
latest, err := parseReleaseData(string(updateBody))
|
||||
if err != nil && noError {
|
||||
return updateMsg
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
errMsg := "Failed to retrieve update notice. Please try again later. Please report this issue at https://github.com/minio/minio/issues"
|
||||
fatalIf(err, errMsg)
|
||||
|
||||
// Verify if the date is not zero.
|
||||
if latest.IsZero() && !noError {
|
||||
fatalIf((errors.New("")), errMsg)
|
||||
if latest.IsZero() {
|
||||
err = errors.New("date should not be zero")
|
||||
return
|
||||
}
|
||||
|
||||
// Is the update latest?.
|
||||
@@ -223,18 +245,26 @@ func getReleaseUpdate(updateURL string, noError bool) updateMessage {
|
||||
}
|
||||
|
||||
// Return update message.
|
||||
return updateMsg
|
||||
return updateMsg, "", nil
|
||||
}
|
||||
|
||||
// main entry point for update command.
|
||||
func mainUpdate(ctx *cli.Context) {
|
||||
// Print all errors as they occur.
|
||||
noError := false
|
||||
// Error out if 'update' command is issued for development based builds.
|
||||
if Version == "DEVELOPMENT.GOGET" {
|
||||
fatalIf(errors.New(""), "Update mechanism is not supported for ‘go get’ based binary builds. Please download official releases from https://minio.io/#minio")
|
||||
}
|
||||
|
||||
// Check for update.
|
||||
var updateMsg updateMessage
|
||||
var errMsg string
|
||||
var err error
|
||||
var secs = time.Second * 3
|
||||
if ctx.Bool("experimental") {
|
||||
console.Println(getReleaseUpdate(minioUpdateExperimentalURL, noError))
|
||||
updateMsg, errMsg, err = getReleaseUpdate(minioUpdateExperimentalURL, secs)
|
||||
} else {
|
||||
console.Println(getReleaseUpdate(minioUpdateStableURL, noError))
|
||||
updateMsg, errMsg, err = getReleaseUpdate(minioUpdateStableURL, secs)
|
||||
}
|
||||
fatalIf(err, errMsg)
|
||||
console.Println(updateMsg)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user