Remove pixel backend
This commit is contained in:
		
							parent
							
								
									38f7185be2
								
							
						
					
					
						commit
						ea32b7899b
					
				| @ -1,321 +0,0 @@ | ||||
| package pixel | ||||
| 
 | ||||
| import "time" | ||||
| import "golang.org/x/image/font" | ||||
| import "github.com/faiface/pixel" | ||||
| import "github.com/faiface/pixel/text" | ||||
| import "github.com/faiface/pixel/imdraw" | ||||
| import "github.com/faiface/pixel/pixelgl" | ||||
| import "golang.org/x/image/font/basicfont" | ||||
| import "git.tebibyte.media/sashakoshka/stone" | ||||
| 
 | ||||
| // Backend represents an instance of the pixel backend | ||||
| type Backend struct { | ||||
| 	window            *pixelgl.Window | ||||
| 	boundsDirty       bool | ||||
| 	windowBounds      pixel.Vec | ||||
| 	fontFace          font.Face | ||||
| 	application       *stone.Application | ||||
| 	config            *stone.Config | ||||
| 	backgroundStamper *imdraw.IMDraw | ||||
| 	fontAtlas         *text.Atlas | ||||
| 	textDrawer        *text.Text | ||||
| 	showBounds        bool | ||||
| 	showCellBounds    bool | ||||
| 
 | ||||
| 	metrics struct { | ||||
| 		cellWidth  int | ||||
| 		cellHeight int | ||||
| 		padding    int | ||||
| 		paddingX   int | ||||
| 		paddingY   int | ||||
| 		descent    int | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Run satisfies the Run method of the Backend interface. Due to the nature of | ||||
| // pixel, this will forcibly bind to the main thread. | ||||
| func (backend *Backend) Run (callback func (application *stone.Application)) { | ||||
| 	// backend.showBounds     = true | ||||
| 	// backend.showCellBounds = true | ||||
| 	 | ||||
| 	if backend.fontFace == nil { | ||||
| 		backend.fontFace = basicfont.Face7x13 | ||||
| 	} | ||||
| 
 | ||||
| 	backend.backgroundStamper = imdraw.New(nil) | ||||
| 	backend.fontAtlas = text.NewAtlas(backend.fontFace, text.ASCII) | ||||
| 	backend.textDrawer = text.New(pixel.V(0, 0), backend.fontAtlas) | ||||
| 
 | ||||
| 	backend.metrics.descent    = int(backend.fontAtlas.Descent()) | ||||
| 	backend.metrics.cellHeight = int(backend.fontAtlas.LineHeight()) | ||||
| 	// FIXME?: this might not be the best way to get the cell width | ||||
| 	faceAdvance, ok := backend.fontFace.GlyphAdvance('M') | ||||
| 	if ok { | ||||
| 		backend.metrics.cellWidth = faceAdvance.Round() | ||||
| 	} else { | ||||
| 		backend.metrics.cellWidth = backend.metrics.cellHeight / 2 | ||||
| 	} | ||||
| 	 | ||||
| 	pixelgl.Run (func () { | ||||
| 		// construct the window, and all that | ||||
| 		var err error | ||||
| 		backend.window, err = pixelgl.NewWindow (pixelgl.WindowConfig { | ||||
| 			Resizable:   true, | ||||
| 			Undecorated: true, | ||||
| 			VSync:       true, | ||||
| 			NoIconify:   true, | ||||
| 			Title:       backend.application.Title(), | ||||
| 			Bounds:      backend.calculateWindowSize(), | ||||
| 		}) | ||||
| 		backend.Poll() | ||||
| 
 | ||||
| 		// TODO: this should return the error and not panic | ||||
| 		if err != nil { panic(err.Error()) } | ||||
| 		callback(backend.application) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // Await fulfills the Await method of the Backend interface. | ||||
| func (backend *Backend) Await (timeout time.Duration) (keepRunning bool) { | ||||
| 	if backend.window == nil { | ||||
| 		panic("call to Backend.Await before window exists") | ||||
| 	} | ||||
| 
 | ||||
| 	backend.draw() | ||||
| 	backend.window.UpdateInputWait(timeout) | ||||
| 	backend.processEvents() | ||||
| 	keepRunning = !backend.window.Closed() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Poll fulfills the Poll method of the Backend interface. | ||||
| func (backend *Backend) Poll () (keepRunning bool) { | ||||
| 	if backend.window == nil { | ||||
| 		panic("call to Backend.Poll before window exists") | ||||
| 	} | ||||
| 
 | ||||
| 	backend.draw() | ||||
| 	backend.window.UpdateInput() | ||||
| 	backend.processEvents() | ||||
| 	keepRunning = !backend.window.Closed() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // SetTitle fulfills the SetTitle method of the Backend interface. | ||||
| func (backend *Backend) SetTitle (title string) { | ||||
| 	if backend.window != nil { | ||||
| 		backend.window.SetTitle(title) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // JustPressed fulfills the JustPressed method of the Backend interface. | ||||
| func (backend *Backend) JustPressed (button stone.Button) (pressed bool) { | ||||
| 	pressed = backend.window.JustPressed(pixelgl.Button(button)) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // JustReleased fulfills the JustReleased method of the Backend interface. | ||||
| func (backend *Backend) JustReleased (button stone.Button) (released bool) { | ||||
| 	released = backend.window.JustReleased(pixelgl.Button(button)) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Pressed fulfills the Pressed method of the Backend interface. | ||||
| func (backend *Backend) Pressed (button stone.Button) (pressed bool) { | ||||
| 	pressed = backend.window.Pressed(pixelgl.Button(button)) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Repeated fulfills the Repeated method of the Backend interface. | ||||
| func (backend *Backend) Repeated (button stone.Button) (repeated bool) { | ||||
| 	repeated = backend.window.Repeated(pixelgl.Button(button)) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Typed fulfills the Typed method of the Backend interface. | ||||
| func (backend *Backend) Typed () (text string) { | ||||
| 	text = backend.window.Typed() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Resized fulfills the Resized method of the Backend interface. | ||||
| func (backend *Backend) Resized () (resized bool) { | ||||
| 	resized = backend.boundsDirty | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // MousePosition fulfills the MousePosition method of the Backend interface. | ||||
| func (backend *Backend) MousePosition () (x, y int) { | ||||
| 	vector := backend.window.MousePosition() | ||||
| 	x = int ( | ||||
| 		(vector.X - float64(backend.metrics.paddingX)) / | ||||
| 		float64(backend.metrics.cellWidth)) | ||||
| 	y = int ( | ||||
| 		(backend.windowBounds.Y - | ||||
| 			vector.Y - | ||||
| 			float64(backend.metrics.paddingY)) / | ||||
| 		float64(backend.metrics.cellHeight)) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // draw renders updates to the screen. | ||||
| func (backend *Backend) draw () { | ||||
| 	// didDrawing := false | ||||
| 	width, height := backend.application.Size() | ||||
| 	 | ||||
| 	if backend.boundsDirty { | ||||
| 		backend.window.Clear ( | ||||
| 			backend.config.Color(stone.ColorApplication)) | ||||
| 		backend.boundsDirty = false | ||||
| 		// didDrawing = true | ||||
| 	} else { | ||||
| 		// clear out dirty cells before drawing them. this is in an else | ||||
| 		// block because if the bounds were dirty, we have already | ||||
| 		// cleared the entire screen. | ||||
| 
 | ||||
| 		backend.backgroundStamper.Clear() | ||||
| 		backend.backgroundStamper.Color = | ||||
| 			backend.config.Color(stone.ColorApplication) | ||||
| 		for x := 0; x < width; x ++ { | ||||
| 			for y := 0; y < height; y ++ { | ||||
| 				clean := backend.application.Clean(x, y) | ||||
| 				if clean { continue } | ||||
| 
 | ||||
| 				backend.backgroundStamper.Push ( | ||||
| 					backend.vectorAtPosition(x, y), | ||||
| 					backend.vectorAtPosition(x + 1, y + 1)) | ||||
| 				backend.backgroundStamper.Rectangle(0) | ||||
| 				// didDrawing = true | ||||
| 
 | ||||
| 				if backend.showCellBounds { | ||||
| 					backend.backgroundStamper.Color = | ||||
| 					backend.config.Color(stone.ColorForeground) | ||||
| 					backend.backgroundStamper.Push ( | ||||
| 						backend.vectorAtPosition(x, y), | ||||
| 						backend.vectorAtPosition(x + 1, y + 1)) | ||||
| 					backend.backgroundStamper.Rectangle(1) | ||||
| 					backend.backgroundStamper.Color = | ||||
| 						backend.config.Color(stone.ColorApplication) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		backend.backgroundStamper.Draw(backend.window) | ||||
| 	} | ||||
| 
 | ||||
| 	backend.textDrawer.Clear() | ||||
| 	backend.textDrawer.Color =  | ||||
| 		backend.config.Color(stone.ColorForeground) | ||||
| 	for x := 0; x < width; x ++ { | ||||
| 		for y := 0; y < height; y ++ { | ||||
| 			clean := backend.application.Clean(x, y) | ||||
| 			if clean { continue } | ||||
| 			backend.application.MarkClean(x, y) | ||||
| 
 | ||||
| 			cell := backend.application.Cell(x, y) | ||||
| 			content := cell.Rune() | ||||
| 			if content < 32 { continue } | ||||
| 			 | ||||
| 			// draw cell | ||||
| 			backend.textDrawer.Dot = pixel.V ( | ||||
| 				float64 ( | ||||
| 					x * backend.metrics.cellWidth + | ||||
| 					backend.metrics.paddingX), | ||||
| 				backend.windowBounds.Y - float64 ( | ||||
| 					(y + 1) * backend.metrics.cellHeight + | ||||
| 					backend.metrics.paddingY - | ||||
| 					backend.metrics.descent)) | ||||
| 			 | ||||
| 			backend.textDrawer.WriteRune(content) | ||||
| 			backend.textDrawer.Draw(backend.window, pixel.IM) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// draw a rectangle around the buffer if we are showing bounds | ||||
| 	if backend.showBounds { | ||||
| 		backend.backgroundStamper.Clear() | ||||
| 		backend.backgroundStamper.Color = | ||||
| 			backend.config.Color(stone.ColorBackground) | ||||
| 		backend.backgroundStamper.Push ( | ||||
| 			backend.vectorAtPosition(0, 0), | ||||
| 			backend.vectorAtPosition(width, height)) | ||||
| 		backend.backgroundStamper.Rectangle(1) | ||||
| 		backend.backgroundStamper.Draw(backend.window) | ||||
| 	} | ||||
| 
 | ||||
| 	backend.window.SwapBuffers() | ||||
| } | ||||
| 
 | ||||
| // processEvents reacts to events recieved from pixel, resizing and | ||||
| // recalculating things as need be. | ||||
| func (backend *Backend) processEvents () { | ||||
| 	newBounds := backend.window.Bounds().Max | ||||
| 	backend.boundsDirty = backend.windowBounds != newBounds | ||||
| 	backend.windowBounds = newBounds | ||||
| 	 | ||||
| 	if backend.boundsDirty { | ||||
| 		// calculate padding | ||||
| 		backend.metrics.padding = | ||||
| 			backend.config.Padding() * | ||||
| 			backend.metrics.cellWidth | ||||
| 		deadArea := float64(backend.metrics.padding * 2) | ||||
| 
 | ||||
| 		// calculate new width and height for buffer | ||||
| 		width := int ( | ||||
| 			(backend.windowBounds.X - deadArea) / | ||||
| 			float64(backend.metrics.cellWidth)) | ||||
| 		height := int ( | ||||
| 			(backend.windowBounds.Y - deadArea) / | ||||
| 			float64(backend.metrics.cellHeight)) | ||||
| 		backend.application.SetSize(width, height) | ||||
| 
 | ||||
| 		// position buffer in center of screen | ||||
| 		frameWidth  := width * backend.metrics.cellWidth | ||||
| 		frameHeight := height * backend.metrics.cellHeight | ||||
| 		backend.metrics.paddingX = (int(backend.windowBounds.X) - frameWidth)  / 2 | ||||
| 		backend.metrics.paddingY = (int(backend.windowBounds.Y) - frameHeight) / 2 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // vectorAtPosition generates a pixel vector at the top left of the specified | ||||
| // cell. | ||||
| func (backend *Backend) vectorAtPosition (x, y int) (vector pixel.Vec) { | ||||
| 	vector = pixel.V ( | ||||
| 		float64 ( | ||||
| 			x * backend.metrics.cellWidth + | ||||
| 			backend.metrics.paddingX), | ||||
| 		backend.windowBounds.Y - float64 ( | ||||
| 			y * backend.metrics.cellHeight + | ||||
| 			backend.metrics.paddingY)) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // calculateWindowSize calculates window bounds based on the internal buffer | ||||
| // size. | ||||
| func (backend *Backend) calculateWindowSize () (bounds pixel.Rect) { | ||||
| 	width, height := backend.application.Size() | ||||
| 	bounds = pixel.R ( | ||||
| 		0, 0, | ||||
| 		float64 ( | ||||
| 			width  * backend.metrics.cellWidth + | ||||
| 			backend.metrics.padding * 2), | ||||
| 		float64 ( | ||||
| 			height * backend.metrics.cellHeight + | ||||
| 			backend.metrics.padding * 2)) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // factory instantiates a pixel backend. | ||||
| func factory (application *stone.Application) (output stone.Backend, err error) { | ||||
| 	backend := &Backend { | ||||
| 		application: application, | ||||
| 		config:      application.Config(), | ||||
| 	} | ||||
| 	output = backend | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // init registers this backend when the program starts. | ||||
| func init () { | ||||
| 	stone.RegisterBackend(factory) | ||||
| } | ||||
							
								
								
									
										7
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								go.mod
									
									
									
									
									
								
							| @ -3,7 +3,6 @@ module git.tebibyte.media/sashakoshka/stone | ||||
| go 1.18 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/faiface/pixel v0.10.0 | ||||
| 	github.com/flopp/go-findfont v0.1.0 | ||||
| 	github.com/jezek/xgb v1.1.0 | ||||
| 	github.com/jezek/xgbutil v0.0.0-20210302171758-530099784e66 | ||||
| @ -13,11 +12,5 @@ require ( | ||||
| require ( | ||||
| 	github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect | ||||
| 	github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect | ||||
| 	github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380 // indirect | ||||
| 	github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 // indirect | ||||
| 	github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 // indirect | ||||
| 	github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 // indirect | ||||
| 	github.com/go-gl/mathgl v0.0.0-20190416160123-c4601bc793c7 // indirect | ||||
| 	github.com/pkg/errors v0.8.1 // indirect | ||||
| 	golang.org/x/text v0.4.0 // indirect | ||||
| ) | ||||
|  | ||||
							
								
								
									
										25
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								go.sum
									
									
									
									
									
								
							| @ -2,40 +2,15 @@ github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJ | ||||
| github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= | ||||
| github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g= | ||||
| github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= | ||||
| github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380 h1:FvZ0mIGh6b3kOITxUnxS3tLZMh7yEoHo75v3/AgUqg0= | ||||
| github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380/go.mod h1:zqnPFFIuYFFxl7uH2gYByJwIVKG7fRqlqQCbzAnHs9g= | ||||
| github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 h1:baVdMKlASEHrj19iqjARrPbaRisD7EuZEVJj6ZMLl1Q= | ||||
| github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3/go.mod h1:VEPNJUlxl5KdWjDvz6Q1l+rJlxF2i6xqDeGuGAxa87M= | ||||
| github.com/faiface/pixel v0.10.0 h1:EHm3ZdQw2Ck4y51cZqFfqQpwLqNHOoXwbNEc9Dijql0= | ||||
| github.com/faiface/pixel v0.10.0/go.mod h1:lU0YYcW77vL0F1CG8oX51GXurymL45MXd57otHNLK7A= | ||||
| github.com/flopp/go-findfont v0.1.0 h1:lPn0BymDUtJo+ZkV01VS3661HL6F4qFlkhcJN55u6mU= | ||||
| github.com/flopp/go-findfont v0.1.0/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw= | ||||
| github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= | ||||
| github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= | ||||
| github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE= | ||||
| github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= | ||||
| github.com/go-gl/mathgl v0.0.0-20190416160123-c4601bc793c7 h1:THttjeRn1iiz69E875U6gAik8KTWk/JYAHoSVpUxBBI= | ||||
| github.com/go-gl/mathgl v0.0.0-20190416160123-c4601bc793c7/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ= | ||||
| github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= | ||||
| github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= | ||||
| github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk= | ||||
| github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= | ||||
| github.com/jezek/xgbutil v0.0.0-20210302171758-530099784e66 h1:+wPhoJD8EH0/bXipIq8Lc2z477jfox9zkXPCJdhvHj8= | ||||
| github.com/jezek/xgbutil v0.0.0-20210302171758-530099784e66/go.mod h1:KACeV+k6b+aoLTVrrurywEbu3UpqoQcQywj4qX8aQKM= | ||||
| github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= | ||||
| github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | ||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||
| github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||
| golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||||
| golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||||
| golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||||
| golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk= | ||||
| golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c= | ||||
| golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user