TIC-80 docs sort of work?
{:fennel-ls {:native-libraries [:tic80]}}
This commit is contained in:
parent
3564167cab
commit
0ddd8f0bf0
@ -22,17 +22,36 @@
|
||||
(when (not (. versions version))
|
||||
(error (.. "fennel-ls doesn't know about lua version " version "\n"
|
||||
"The allowed versions are: "
|
||||
(fennel.view (icollect [key (pairs versions)]
|
||||
key)))))
|
||||
(fennel.view (doto (icollect [key (pairs versions)] key) table.sort)))))
|
||||
(. versions version))
|
||||
|
||||
(local libraries
|
||||
{:tic80 (require :fennel-ls.docs.tic80)})
|
||||
|
||||
(fn get-native-library [library]
|
||||
(when (not (. libraries library))
|
||||
(error (.. "fennel-ls doesn't know about native library " library "\n"
|
||||
"The builtin libraries are: "
|
||||
(fennel.view (doto (icollect [key (pairs libraries)] key) table.sort)))))
|
||||
(. libraries library))
|
||||
|
||||
(fn get-all-globals [self]
|
||||
(icollect [name (pairs (get-lua-version self.configuration.version))]
|
||||
name))
|
||||
(let [result []]
|
||||
(each [_ library (ipairs self.configuration.native-libraries)]
|
||||
(icollect [name (pairs (get-native-library library)) &into result]
|
||||
name))
|
||||
(icollect [name (pairs (get-lua-version self.configuration.version)) &into result]
|
||||
name)))
|
||||
|
||||
(fn get-global [self global-name]
|
||||
(. (get-lua-version self.configuration.version)
|
||||
global-name))
|
||||
(or
|
||||
(accumulate [result nil
|
||||
_ library (ipairs self.configuration.native-libraries)
|
||||
&until result]
|
||||
(. (get-native-library library)
|
||||
global-name))
|
||||
(. (get-lua-version self.configuration.version)
|
||||
global-name)))
|
||||
|
||||
(fn get-builtin [_self builtin-name]
|
||||
(or (. specials builtin-name)
|
||||
|
||||
@ -1,25 +1,32 @@
|
||||
;; auto-generated by `make docs` from fennel-ls. Contents come from https://tic80.com/learn
|
||||
{:BDR {:metadata {:fnl/arglist ["row"]
|
||||
{:BDR {:binding "BDR"
|
||||
:metadata {:fnl/arglist ["row"]
|
||||
:fnl/docstring "Allows you to execute code between the drawing of each fullscreen scanline, for example, to manipulate the palette.
|
||||
"}}
|
||||
:BOOT {:metadata {:fnl/docstring "Startup function.
|
||||
:BOOT {:binding "BOOT"
|
||||
:metadata {:fnl/docstring "Startup function.
|
||||
"}}
|
||||
:MENU {:metadata {:fnl/arglist ["index"]
|
||||
:MENU {:binding "MENU"
|
||||
:metadata {:fnl/arglist ["index"]
|
||||
:fnl/docstring "Game Menu handler.
|
||||
"}}
|
||||
:SCN {:metadata {:fnl/arglist ["row"]
|
||||
:SCN {:binding "SCN"
|
||||
:metadata {:fnl/arglist ["row"]
|
||||
:fnl/docstring "Allows you to execute code between the drawing of each scanline, for example, to manipulate the palette.
|
||||
"}}
|
||||
:TIC {:metadata {:fnl/arglist {}
|
||||
:TIC {:binding "TIC"
|
||||
:metadata {:fnl/arglist {}
|
||||
:fnl/docstring "Main function. It's called at 60fps (60 times every second).
|
||||
"}}
|
||||
:btn {:metadata {:fnl/arglist ["id"]
|
||||
:btn {:binding "btn"
|
||||
:metadata {:fnl/arglist ["id"]
|
||||
:fnl/docstring "This function allows you to read the status of one of the buttons attached to TIC.
|
||||
The function returns true if the key with the supplied id is currently in the pressed state.
|
||||
It remains true for as long as the key is held down.
|
||||
If you want to test if a key was just pressed, use `btnp()` instead.
|
||||
"}}
|
||||
:btnp {:metadata {:fnl/arglist ["id" "?hold" "?period"]
|
||||
:btnp {:binding "btnp"
|
||||
:metadata {:fnl/arglist ["id" "?hold" "?period"]
|
||||
:fnl/docstring "This function allows you to read the status of one of TIC's buttons.
|
||||
It returns true only if the key has been pressed since the last frame.
|
||||
You can also use the optional hold and period parameters which allow you to check if a button is being held down.
|
||||
@ -27,39 +34,48 @@ After the time specified by hold has elapsed, btnp will return true each time pe
|
||||
For example, to re-examine the state of button `0` after 2 seconds and continue to check its state every 1/10th of a second, you would use btnp(0, 120, 6).
|
||||
Since time is expressed in ticks and TIC runs at 60 frames per second, we use the value of 120 to wait 2 seconds and 6 ticks (ie 60/10) as the interval for re-checking.
|
||||
"}}
|
||||
:circ {:metadata {:fnl/arglist ["x" "y" "radius" "color"]
|
||||
:circ {:binding "circ"
|
||||
:metadata {:fnl/arglist ["x" "y" "radius" "color"]
|
||||
:fnl/docstring "This function draws a filled circle of the desired radius and color with its center at x, y.
|
||||
It uses the Bresenham algorithm.
|
||||
"}}
|
||||
:circb {:metadata {:fnl/arglist ["x" "y" "radius" "color"]
|
||||
:circb {:binding "circb"
|
||||
:metadata {:fnl/arglist ["x" "y" "radius" "color"]
|
||||
:fnl/docstring "Draws the circumference of a circle with its center at x, y using the radius and color requested.
|
||||
It uses the Bresenham algorithm.
|
||||
"}}
|
||||
:clip {:metadata {:fnl/arglist ["x" "y" "width" "height"]
|
||||
:clip {:binding "clip"
|
||||
:metadata {:fnl/arglist ["x" "y" "width" "height"]
|
||||
:fnl/docstring "This function limits drawing to a clipping region or `viewport` defined by x,y,w,h.
|
||||
Things drawn outside of this area will not be visible.
|
||||
Calling clip() with no parameters will reset the drawing area to the entire screen.
|
||||
"}}
|
||||
:cls {:metadata {:fnl/arglist ["?color"]
|
||||
:cls {:binding "cls"
|
||||
:metadata {:fnl/arglist ["?color"]
|
||||
:fnl/docstring "Clear the screen.
|
||||
When called this function clear all the screen using the color passed as argument.
|
||||
If no parameter is passed first color (0) is used.
|
||||
"}}
|
||||
:elli {:metadata {:fnl/arglist ["x" "y" "a" "b" "color"]
|
||||
:elli {:binding "elli"
|
||||
:metadata {:fnl/arglist ["x" "y" "a" "b" "color"]
|
||||
:fnl/docstring "This function draws a filled ellipse of the desired a, b radiuses and color with its center at x, y.
|
||||
It uses the Bresenham algorithm.
|
||||
"}}
|
||||
:ellib {:metadata {:fnl/arglist ["x" "y" "a" "b" "color"]
|
||||
:ellib {:binding "ellib"
|
||||
:metadata {:fnl/arglist ["x" "y" "a" "b" "color"]
|
||||
:fnl/docstring "This function draws an ellipse border with the desired radiuses a b and color with its center at x, y.
|
||||
It uses the Bresenham algorithm.
|
||||
"}}
|
||||
:exit {:metadata {:fnl/arglist {}
|
||||
:exit {:binding "exit"
|
||||
:metadata {:fnl/arglist {}
|
||||
:fnl/docstring "Interrupts program execution and returns to the console when the TIC function ends.
|
||||
"}}
|
||||
:fget {:metadata {:fnl/arglist ["sprite_id" "flag"]
|
||||
:fget {:binding "fget"
|
||||
:metadata {:fnl/arglist ["sprite_id" "flag"]
|
||||
:fnl/docstring "Returns true if the specified flag of the sprite is set. See `fset()` for more details.
|
||||
"}}
|
||||
:font {:metadata {:fnl/arglist ["text"
|
||||
:font {:binding "font"
|
||||
:metadata {:fnl/arglist ["text"
|
||||
"x"
|
||||
"y"
|
||||
"chromakey"
|
||||
@ -72,22 +88,27 @@ It uses the Bresenham algorithm.
|
||||
To simply print to the screen, check out `print()`.
|
||||
To print to the console, check out `trace()`.
|
||||
"}}
|
||||
:fset {:metadata {:fnl/arglist ["sprite_id" "flag" "bool"]
|
||||
:fset {:binding "fset"
|
||||
:metadata {:fnl/arglist ["sprite_id" "flag" "bool"]
|
||||
:fnl/docstring "Each sprite has eight flags which can be used to store information or signal different conditions.
|
||||
For example, flag 0 might be used to indicate that the sprite is invisible, flag 6 might indicate that the flag should be draw scaled etc.
|
||||
See algo `fget()`.
|
||||
"}}
|
||||
:key {:metadata {:fnl/arglist ["?code"]
|
||||
:key {:binding "key"
|
||||
:metadata {:fnl/arglist ["?code"]
|
||||
:fnl/docstring "The function returns true if the key denoted by keycode is pressed.
|
||||
"}}
|
||||
:keyp {:metadata {:fnl/arglist ["?code" "?hold" "?period"]
|
||||
:keyp {:binding "keyp"
|
||||
:metadata {:fnl/arglist ["?code" "?hold" "?period"]
|
||||
:fnl/docstring "This function returns true if the given key is pressed but wasn't pressed in the previous frame.
|
||||
Refer to `btnp()` for an explanation of the optional hold and period parameters.
|
||||
"}}
|
||||
:line {:metadata {:fnl/arglist ["x0" "y0" "x1" "y1" "color"]
|
||||
:line {:binding "line"
|
||||
:metadata {:fnl/arglist ["x0" "y0" "x1" "y1" "color"]
|
||||
:fnl/docstring "Draws a straight line from point (x0,y0) to point (x1,y1) in the specified color.
|
||||
"}}
|
||||
:map {:metadata {:fnl/arglist ["?x"
|
||||
:map {:binding "map"
|
||||
:metadata {:fnl/arglist ["?x"
|
||||
"?y"
|
||||
"?w"
|
||||
"?h"
|
||||
@ -107,27 +128,33 @@ Some examples include changing sprites to open doorways, hiding sprites used to
|
||||
The tilemap is laid out sequentially in RAM - writing 1 to 0x08000 will cause tile(sprite) #1 to appear at top left when map() is called.
|
||||
To set the tile immediately below this we need to write to 0x08000 + 240, ie 0x080F0.
|
||||
"}}
|
||||
:memcpy {:metadata {:fnl/arglist ["dest" "source" "size"]
|
||||
:memcpy {:binding "memcpy"
|
||||
:metadata {:fnl/arglist ["dest" "source" "size"]
|
||||
:fnl/docstring "This function allows you to copy a continuous block of TIC's 96K RAM from one address to another.
|
||||
Addresses are specified are in hexadecimal format, values are decimal.
|
||||
"}}
|
||||
:memset {:metadata {:fnl/arglist ["dest" "value" "size"]
|
||||
:memset {:binding "memset"
|
||||
:metadata {:fnl/arglist ["dest" "value" "size"]
|
||||
:fnl/docstring "This function allows you to set a continuous block of any part of TIC's RAM to the same value.
|
||||
The address is specified in hexadecimal format, the value in decimal.
|
||||
"}}
|
||||
:mget {:metadata {:fnl/arglist ["x" "y"]
|
||||
:mget {:binding "mget"
|
||||
:metadata {:fnl/arglist ["x" "y"]
|
||||
:fnl/docstring "Gets the sprite id at the given x and y map coordinate.
|
||||
"}}
|
||||
:mouse {:metadata {:fnl/arglist {}
|
||||
:mouse {:binding "mouse"
|
||||
:metadata {:fnl/arglist {}
|
||||
:fnl/docstring "This function returns the mouse coordinates and a boolean value for the state of each mouse button,with true indicating that a button is pressed.
|
||||
"}}
|
||||
:mset {:metadata {:fnl/arglist ["x" "y" "tile_id"]
|
||||
:mset {:binding "mset"
|
||||
:metadata {:fnl/arglist ["x" "y" "tile_id"]
|
||||
:fnl/docstring "This function will change the tile at the specified map coordinates.
|
||||
By default, changes made are only kept while the current game is running.
|
||||
To make permanent changes to the map, see `sync()`.
|
||||
Related: `map()` `mget()` `sync()`.
|
||||
"}}
|
||||
:music {:metadata {:fnl/arglist ["?track"
|
||||
:music {:binding "music"
|
||||
:metadata {:fnl/arglist ["?track"
|
||||
"?frame"
|
||||
"?row"
|
||||
"?loop"
|
||||
@ -137,7 +164,8 @@ Related: `map()` `mget()` `sync()`.
|
||||
:fnl/docstring "This function starts playing a track created in the Music Editor.
|
||||
Call without arguments to stop the music.
|
||||
"}}
|
||||
:peek {:metadata {:fnl/arglist ["addr" "?bits"]
|
||||
:peek {:binding "peek"
|
||||
:metadata {:fnl/arglist ["addr" "?bits"]
|
||||
:fnl/docstring "This function allows to read the memory from TIC.
|
||||
It's useful to access resources created with the integrated tools like sprite, maps, sounds, cartridges data?
|
||||
Never dream to sound a sprite?
|
||||
@ -145,25 +173,30 @@ Address are in hexadecimal format but values are decimal.
|
||||
To write to a memory address, use `poke()`.
|
||||
`bits` allowed to be 1,2,4,8.
|
||||
"}}
|
||||
:peek1 {:metadata {:fnl/arglist ["addr"]
|
||||
:peek1 {:binding "peek1"
|
||||
:metadata {:fnl/arglist ["addr"]
|
||||
:fnl/docstring "This function enables you to read single bit values from TIC's RAM.
|
||||
The address is often specified in hexadecimal format.
|
||||
"}}
|
||||
:peek2 {:metadata {:fnl/arglist ["addr"]
|
||||
:peek2 {:binding "peek2"
|
||||
:metadata {:fnl/arglist ["addr"]
|
||||
:fnl/docstring "This function enables you to read two bits values from TIC's RAM.
|
||||
The address is often specified in hexadecimal format.
|
||||
"}}
|
||||
:peek4 {:metadata {:fnl/arglist ["addr"]
|
||||
:peek4 {:binding "peek4"
|
||||
:metadata {:fnl/arglist ["addr"]
|
||||
:fnl/docstring "This function enables you to read values from TIC's RAM.
|
||||
The address is often specified in hexadecimal format.
|
||||
See 'poke4()' for detailed information on how nibble addressing compares with byte addressing.
|
||||
"}}
|
||||
:pix {:metadata {:fnl/arglist ["x" "y" "color"]
|
||||
:pix {:binding "pix"
|
||||
:metadata {:fnl/arglist ["x" "y" "color"]
|
||||
:fnl/docstring "This function can read or write pixel color values.
|
||||
When called with a color parameter, the pixel at the specified coordinates is set to that color.
|
||||
Calling the function without a color parameter returns the color of the pixel at the specified position.
|
||||
"}}
|
||||
:pmem {:metadata {:fnl/arglist ["index" "value"]
|
||||
:pmem {:binding "pmem"
|
||||
:metadata {:fnl/arglist ["index" "value"]
|
||||
:fnl/docstring "This function allows you to save and retrieve data in one of the 256 individual 32-bit slots available in the cartridge's persistent memory.
|
||||
This is useful for saving high-scores, level advancement or achievements.
|
||||
The data is stored as unsigned 32-bit integers (from 0 to 4294967295).
|
||||
@ -173,27 +206,32 @@ Tips:
|
||||
- Use `saveid:` with a personalized string in the header metadata to override the default MD5 calculation.
|
||||
This allows the user to update a cart without losing their saved data.
|
||||
"}}
|
||||
:poke {:metadata {:fnl/arglist ["addr" "value" "?bits"]
|
||||
:poke {:binding "poke"
|
||||
:metadata {:fnl/arglist ["addr" "value" "?bits"]
|
||||
:fnl/docstring "This function allows you to write a single byte to any address in TIC's RAM.
|
||||
The address should be specified in hexadecimal format, the value in decimal.
|
||||
`bits` allowed to be 1,2,4,8.
|
||||
"}}
|
||||
:poke1 {:metadata {:fnl/arglist ["addr" "value"]
|
||||
:poke1 {:binding "poke1"
|
||||
:metadata {:fnl/arglist ["addr" "value"]
|
||||
:fnl/docstring "This function allows you to write single bit values directly to RAM.
|
||||
The address is often specified in hexadecimal format.
|
||||
"}}
|
||||
:poke2 {:metadata {:fnl/arglist ["addr" "value"]
|
||||
:poke2 {:binding "poke2"
|
||||
:metadata {:fnl/arglist ["addr" "value"]
|
||||
:fnl/docstring "This function allows you to write two bits values directly to RAM.
|
||||
The address is often specified in hexadecimal format.
|
||||
"}}
|
||||
:poke4 {:metadata {:fnl/arglist ["addr" "value"]
|
||||
:poke4 {:binding "poke4"
|
||||
:metadata {:fnl/arglist ["addr" "value"]
|
||||
:fnl/docstring "This function allows you to write directly to RAM.
|
||||
The address is often specified in hexadecimal format.
|
||||
For both peek4 and poke4 RAM is addressed in 4 bit segments (nibbles).
|
||||
Therefore, to access the the RAM at byte address 0x4000
|
||||
you would need to access both the 0x8000 and 0x8001 nibble addresses.
|
||||
"}}
|
||||
:print {:metadata {:fnl/arglist ["text"
|
||||
:print {:binding "print"
|
||||
:metadata {:fnl/arglist ["text"
|
||||
"?x"
|
||||
"?y"
|
||||
"?color"
|
||||
@ -208,18 +246,22 @@ Tips:
|
||||
- To use a custom rastered font, check out `font()`.
|
||||
- To print to the console, check out `trace()`.
|
||||
"}}
|
||||
:rect {:metadata {:fnl/arglist ["x" "y" "w" "h" "color"]
|
||||
:rect {:binding "rect"
|
||||
:metadata {:fnl/arglist ["x" "y" "w" "h" "color"]
|
||||
:fnl/docstring "This function draws a filled rectangle of the desired size and color at the specified position.
|
||||
If you only need to draw the the border or outline of a rectangle (ie not filled) see `rectb()`.
|
||||
"}}
|
||||
:rectb {:metadata {:fnl/arglist ["x" "y" "w" "h" "color"]
|
||||
:rectb {:binding "rectb"
|
||||
:metadata {:fnl/arglist ["x" "y" "w" "h" "color"]
|
||||
:fnl/docstring "This function draws a one pixel thick rectangle border at the position requested.
|
||||
If you need to fill the rectangle with a color, see `rect()` instead.
|
||||
"}}
|
||||
:reset {:metadata {:fnl/arglist {}
|
||||
:reset {:binding "reset"
|
||||
:metadata {:fnl/arglist {}
|
||||
:fnl/docstring "Resets the cartridge. To return to the console, see the `exit()`.
|
||||
"}}
|
||||
:sfx {:metadata {:fnl/arglist ["id"
|
||||
:sfx {:binding "sfx"
|
||||
:metadata {:fnl/arglist ["id"
|
||||
"?note"
|
||||
"?duration"
|
||||
"?channel"
|
||||
@ -240,7 +282,8 @@ The `channel` parameter indicates which of the four channels to use. Allowed val
|
||||
The `volume` can be between 0 and 15.
|
||||
The `speed` in the range -4 to 3 can be specified and means how many `ticks+1` to play each step, so speed==0 means 1 tick per step.
|
||||
"}}
|
||||
:spr {:metadata {:fnl/arglist ["id"
|
||||
:spr {:binding "spr"
|
||||
:metadata {:fnl/arglist ["id"
|
||||
"x"
|
||||
"y"
|
||||
"?colorkey"
|
||||
@ -264,17 +307,20 @@ When you rotate the sprite, it's rotated clockwise in 90 steps:
|
||||
- 3 = 270 rotation
|
||||
You can draw a composite sprite (consisting of a rectangular region of sprites from the sprite sheet) by specifying the `w` and `h` parameters (which default to 1).
|
||||
"}}
|
||||
:sync {:metadata {:fnl/arglist ["?mask" "?bank" "?tocart"]
|
||||
:sync {:binding "sync"
|
||||
:metadata {:fnl/arglist ["?mask" "?bank" "?tocart"]
|
||||
:fnl/docstring "The pro version of TIC-80 contains 8 memory banks.
|
||||
To switch between these banks, sync can be used to either load contents from a memory bank to runtime, or save contents from the active runtime to a bank.
|
||||
The function can only be called once per frame.If you have manipulated the runtime memory (e.g. by using mset), you can reset the active state by calling sync(0,0,false).
|
||||
This resets the whole runtime memory to the contents of bank 0.Note that sync is not used to load code from banks; this is done automatically.
|
||||
"}}
|
||||
:time {:metadata {:fnl/arglist {}
|
||||
:time {:binding "time"
|
||||
:metadata {:fnl/arglist {}
|
||||
:fnl/docstring "This function returns the number of milliseconds elapsed since the cartridge began execution.
|
||||
Useful for keeping track of time, animating items and triggering events.
|
||||
"}}
|
||||
:trace {:metadata {:fnl/arglist ["message" "?color"]
|
||||
:trace {:binding "trace"
|
||||
:metadata {:fnl/arglist ["message" "?color"]
|
||||
:fnl/docstring "This is a service function, useful for debugging your code.
|
||||
It prints the message parameter to the console in the (optional) color specified.
|
||||
|
||||
@ -282,17 +328,21 @@ Tips:
|
||||
- The Lua concatenator for strings is .. (two points).
|
||||
- Use console cls command to clear the output from trace.
|
||||
"}}
|
||||
:tri {:metadata {:fnl/arglist ["x1" "y1" "x2" "y2" "x3" "y3" "color"]
|
||||
:tri {:binding "tri"
|
||||
:metadata {:fnl/arglist ["x1" "y1" "x2" "y2" "x3" "y3" "color"]
|
||||
:fnl/docstring "This function draws a triangle filled with color, using the supplied vertices.
|
||||
"}}
|
||||
:trib {:metadata {:fnl/arglist ["x1" "y1" "x2" "y2" "x3" "y3" "color"]
|
||||
:trib {:binding "trib"
|
||||
:metadata {:fnl/arglist ["x1" "y1" "x2" "y2" "x3" "y3" "color"]
|
||||
:fnl/docstring "This function draws a triangle border with color, using the supplied vertices.
|
||||
"}}
|
||||
:tstamp {:metadata {:fnl/arglist {}
|
||||
:tstamp {:binding "tstamp"
|
||||
:metadata {:fnl/arglist {}
|
||||
:fnl/docstring "This function returns the number of seconds elapsed since January 1st, 1970.
|
||||
Useful for creating persistent games which evolve over time between plays.
|
||||
"}}
|
||||
:ttri {:metadata {:fnl/arglist ["x1"
|
||||
:ttri {:binding "ttri"
|
||||
:metadata {:fnl/arglist ["x1"
|
||||
"y1"
|
||||
"x2"
|
||||
"y2"
|
||||
|
||||
@ -105,6 +105,7 @@ entire fennel-ls project is referring to the same object."
|
||||
:var-never-set (option true)
|
||||
:op-with-no-arguments (option true)
|
||||
:multival-in-middle-of-call (option true)}
|
||||
:native-libraries (option [])
|
||||
:extra-globals (option "")})
|
||||
|
||||
(λ make-configuration [?c]
|
||||
|
||||
@ -61,7 +61,16 @@
|
||||
(faith.= [] diagnostics))
|
||||
nil)
|
||||
|
||||
(fn test-native-libaries []
|
||||
(let [{:diagnostics bad} (create-client-with-files "(print btn)"
|
||||
{:settings {}})
|
||||
{:diagnostics good} (create-client-with-files "(print btn)"
|
||||
{:settings {:fennel-ls {:native-libraries [:tic80]}}})]
|
||||
(faith.not= [] bad)
|
||||
(faith.= [] good)))
|
||||
|
||||
{: test-path
|
||||
: test-extra-globals
|
||||
: test-lints
|
||||
: test-initialization-options}
|
||||
: test-initialization-options
|
||||
: test-native-libaries}
|
||||
|
||||
@ -25,7 +25,8 @@
|
||||
"([_%w]+)%s+`([^`]+)`%s(.-)\n### ")]
|
||||
(let [arglist (markdown->arglist args)]
|
||||
(values name {:metadata {:fnl/arglist arglist
|
||||
:fnl/docstring docs}})))))
|
||||
:fnl/docstring docs}
|
||||
:binding name})))))
|
||||
|
||||
(fn convert [contents]
|
||||
(fennel.view (markdown->data contents)))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user