ui: revive the curses UI, now named hledger-ui
This commit is contained in:
		
							parent
							
								
									25146b09e2
								
							
						
					
					
						commit
						207ae772d4
					
				
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							| @ -5,11 +5,12 @@ | |||||||
| hledger is a computer program for easily tracking money, time, or other commodities, | hledger is a computer program for easily tracking money, time, or other commodities, | ||||||
| on unix, mac and windows (and web-capable mobile devices, to some extent). | on unix, mac and windows (and web-capable mobile devices, to some extent). | ||||||
| 
 | 
 | ||||||
| It is first a command-line tool, but there is also a web interface | It is first a command-line tool, but there are also curses-style and | ||||||
| and a Haskell library (http://hackage.haskell.org/package/hledger-lib) for | web interfaces, and a Haskell library | ||||||
| building your own programs and scripts (hledger is written in Haskell). | (http://hackage.haskell.org/package/hledger-lib) for building your own | ||||||
| hledger was inspired by and is largely compatible with Ledger. | programs and scripts (hledger is written in Haskell).  hledger was | ||||||
| hledger is free software available under the GNU General Public License v3+. | inspired by and is largely compatible with Ledger.  hledger is free | ||||||
|  | software available under the GNU General Public License v3+. | ||||||
| 
 | 
 | ||||||
| hledger aims to help both computer experts and regular folks | hledger aims to help both computer experts and regular folks | ||||||
| to gain clarity and control in their finances and time management, | to gain clarity and control in their finances and time management, | ||||||
|  | |||||||
| @ -1,21 +0,0 @@ | |||||||
| {-| |  | ||||||
| Re-export the modules of the hledger-vty program. |  | ||||||
| -} |  | ||||||
| 
 |  | ||||||
| module Hledger.Vty ( |  | ||||||
|                      module Hledger.Vty.Main, |  | ||||||
|                      module Hledger.Vty.Options, |  | ||||||
|                      tests_Hledger_Vty |  | ||||||
|               ) |  | ||||||
| where |  | ||||||
| import Test.HUnit |  | ||||||
| 
 |  | ||||||
| import Hledger.Vty.Main |  | ||||||
| import Hledger.Vty.Options |  | ||||||
| 
 |  | ||||||
| tests_Hledger_Vty :: Test |  | ||||||
| tests_Hledger_Vty = TestList |  | ||||||
|  [ |  | ||||||
|  --  tests_Hledger_Vty_Main |  | ||||||
|  --  tests_Hledger_Vty_Options |  | ||||||
|  ] |  | ||||||
| @ -1,5 +0,0 @@ | |||||||
| A curses-style console interface for the hledger accounting tool. |  | ||||||
| It allows browsing the balance, register and print reports with cursor keys and scrolling, |  | ||||||
| and was actually quite useful. |  | ||||||
| 
 |  | ||||||
| Warning, this package has been unmaintained since 2011 and will not install. |  | ||||||
| @ -1,8 +0,0 @@ | |||||||
| packages: |  | ||||||
| - '../../hledger-lib' |  | ||||||
| - '../../hledger' |  | ||||||
| - '.' |  | ||||||
| flags: |  | ||||||
| resolver: lts-3.0 |  | ||||||
| extra-deps: |  | ||||||
| - vty-5.2.10 |  | ||||||
							
								
								
									
										21
									
								
								hledger-ui/Hledger/UI.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								hledger-ui/Hledger/UI.hs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | {-| | ||||||
|  | Re-export the modules of the hledger-ui program. | ||||||
|  | -} | ||||||
|  | 
 | ||||||
|  | module Hledger.UI ( | ||||||
|  |                      module Hledger.UI.Main, | ||||||
|  |                      module Hledger.UI.Options, | ||||||
|  |                      tests_Hledger_UI | ||||||
|  |               ) | ||||||
|  | where | ||||||
|  | import Test.HUnit | ||||||
|  | 
 | ||||||
|  | import Hledger.UI.Main | ||||||
|  | import Hledger.UI.Options | ||||||
|  | 
 | ||||||
|  | tests_Hledger_UI :: Test | ||||||
|  | tests_Hledger_UI = TestList | ||||||
|  |  [ | ||||||
|  |  --  tests_Hledger_UI_Main | ||||||
|  |  --  tests_Hledger_UI_Options | ||||||
|  |  ] | ||||||
| @ -1,10 +1,10 @@ | |||||||
| {-| | {-| | ||||||
| hledger-vty - a hledger add-on providing a curses-style interface. | hledger-ui - a hledger add-on providing a curses-style interface. | ||||||
| Copyright (c) 2007-2011 Simon Michael <simon@joyful.com> | Copyright (c) 2007-2011 Simon Michael <simon@joyful.com> | ||||||
| Released under GPL version 3 or later. | Released under GPL version 3 or later. | ||||||
| -} | -} | ||||||
| 
 | 
 | ||||||
| module Hledger.Vty.Main (main) where | module Hledger.UI.Main (main) where | ||||||
| 
 | 
 | ||||||
| import Control.Monad | import Control.Monad | ||||||
| import Data.List | import Data.List | ||||||
| @ -16,25 +16,25 @@ import System.Exit | |||||||
| 
 | 
 | ||||||
| import Hledger | import Hledger | ||||||
| import Hledger.Cli hiding (progname,prognameandversion,green) | import Hledger.Cli hiding (progname,prognameandversion,green) | ||||||
| import Hledger.Vty.Options | import Hledger.UI.Options | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| main :: IO () | main :: IO () | ||||||
| main = do | main = do | ||||||
|   opts <- getHledgerVtyOpts |   opts <- getHledgerUIOpts | ||||||
|   -- when (debug_ $ cliopts_ opts) $ printf "%s\n" prognameandversion >> printf "opts: %s\n" (show opts) |   -- when (debug_ $ cliopts_ opts) $ printf "%s\n" prognameandversion >> printf "opts: %s\n" (show opts) | ||||||
|   runWith opts |   runWith opts | ||||||
| 
 | 
 | ||||||
| runWith :: VtyOpts -> IO () | runWith :: UIOpts -> IO () | ||||||
| runWith opts = run opts | runWith opts = run opts | ||||||
|     where |     where | ||||||
|       run opts |       run opts | ||||||
|           | "help" `inRawOpts` (rawopts_ $ cliopts_ opts)            = putStr (showModeHelp vtymode) >> exitSuccess |           | "help" `inRawOpts` (rawopts_ $ cliopts_ opts)            = putStr (showModeHelp uimode) >> exitSuccess | ||||||
|           | "version" `inRawOpts` (rawopts_ $ cliopts_ opts)         = putStrLn prognameandversion >> exitSuccess |           | "version" `inRawOpts` (rawopts_ $ cliopts_ opts)         = putStrLn prognameandversion >> exitSuccess | ||||||
|           | "binary-filename" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStrLn (binaryfilename progname) |           | "binary-filename" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStrLn (binaryfilename progname) | ||||||
|           | otherwise                                          = withJournalDo' opts vty |           | otherwise                                          = withJournalDo' opts ui | ||||||
| 
 | 
 | ||||||
| withJournalDo' :: VtyOpts -> (VtyOpts -> Journal -> IO ()) -> IO () | withJournalDo' :: UIOpts -> (UIOpts -> Journal -> IO ()) -> IO () | ||||||
| withJournalDo' opts cmd = do | withJournalDo' opts cmd = do | ||||||
|   -- journalFilePathFromOpts (cliopts_ opts) >>= readJournalFile Nothing >>= |   -- journalFilePathFromOpts (cliopts_ opts) >>= readJournalFile Nothing >>= | ||||||
|   --   either error' (cmd opts . journalApplyAliases (aliasesFromOpts $ cliopts_ opts)) |   --   either error' (cmd opts . journalApplyAliases (aliasesFromOpts $ cliopts_ opts)) | ||||||
| @ -42,17 +42,17 @@ withJournalDo' opts cmd = do | |||||||
|   (head `fmap` journalFilePathFromOpts (cliopts_ opts)) >>= readJournalFile Nothing Nothing True >>= |   (head `fmap` journalFilePathFromOpts (cliopts_ opts)) >>= readJournalFile Nothing Nothing True >>= | ||||||
|     either error' (cmd opts . journalApplyAliases (aliasesFromOpts $ cliopts_ opts)) |     either error' (cmd opts . journalApplyAliases (aliasesFromOpts $ cliopts_ opts)) | ||||||
| 
 | 
 | ||||||
| helpmsg = "(b)alance, (r)egister, (p)rint, (right) to drill down, (left) to back up, (q)uit" | helpmsg = "(right) drill down, (left) back up, (q)uit" | ||||||
| 
 | 
 | ||||||
| instance Show Vty where show = const "a Vty" | instance Show Vty where show = const "a Vty" | ||||||
| 
 | 
 | ||||||
| -- | The application state when running the vty command. | -- | The application state when running the ui command. | ||||||
| data AppState = AppState { | data AppState = AppState { | ||||||
|      av :: Vty                   -- ^ the vty context |      av :: Vty                   -- ^ the vty context | ||||||
|     ,aw :: Int                   -- ^ window width |     ,aw :: Int                   -- ^ window width | ||||||
|     ,ah :: Int                   -- ^ window height |     ,ah :: Int                   -- ^ window height | ||||||
|     ,amsg :: String              -- ^ status message |     ,amsg :: String              -- ^ status message | ||||||
|     ,aopts :: VtyOpts            -- ^ command-line opts |     ,aopts :: UIOpts            -- ^ command-line opts | ||||||
|     ,aargs :: [String]           -- ^ command-line args at startup |     ,aargs :: [String]           -- ^ command-line args at startup | ||||||
|     ,ajournal :: Journal         -- ^ parsed journal |     ,ajournal :: Journal         -- ^ parsed journal | ||||||
|     ,abuf :: [String]            -- ^ lines of the current buffered view |     ,abuf :: [String]            -- ^ lines of the current buffered view | ||||||
| @ -75,11 +75,11 @@ data Screen = BalanceScreen     -- ^ like hledger balance, shows accounts | |||||||
|             -- | LedgerScreen      -- ^ shows the raw journal entries |             -- | LedgerScreen      -- ^ shows the raw journal entries | ||||||
|               deriving (Eq,Show) |               deriving (Eq,Show) | ||||||
| 
 | 
 | ||||||
| -- | Run the vty (curses-style) ui. | -- | Run the curses-style ui. | ||||||
| vty :: VtyOpts -> Journal -> IO () | ui :: UIOpts -> Journal -> IO () | ||||||
| vty opts j = do | ui opts j = do | ||||||
|   cfg <- standardIOConfig |   cfg <- standardIOConfig | ||||||
|   v <- mkVty cfg |   vty <- mkVty cfg | ||||||
| 
 | 
 | ||||||
|   -- let line0 = string (defAttr ` withForeColor ` green) "first line" |   -- let line0 = string (defAttr ` withForeColor ` green) "first line" | ||||||
|   --     line1 = string (defAttr ` withBackColor ` blue) "second line" |   --     line1 = string (defAttr ` withBackColor ` blue) "second line" | ||||||
| @ -95,7 +95,7 @@ vty opts j = do | |||||||
|   d <- getCurrentDay |   d <- getCurrentDay | ||||||
|   let a = enter d BalanceScreen (words' $ query_ $ reportopts_ $ cliopts_ opts) |   let a = enter d BalanceScreen (words' $ query_ $ reportopts_ $ cliopts_ opts) | ||||||
|           AppState { |           AppState { | ||||||
|                   av=v |                   av=vty | ||||||
|                  ,aw=w |                  ,aw=w | ||||||
|                  ,ah=h |                  ,ah=h | ||||||
|                  ,amsg=helpmsg |                  ,amsg=helpmsg | ||||||
| @ -110,15 +110,15 @@ vty opts j = do | |||||||
| -- | Update the screen, wait for the next event, repeat. | -- | Update the screen, wait for the next event, repeat. | ||||||
| go :: AppState -> IO () | go :: AppState -> IO () | ||||||
| go a@AppState{av=av,aopts=opts} = do | go a@AppState{av=av,aopts=opts} = do | ||||||
|   when (not $ debug_vty_ opts) $ update av (renderScreen a) |   when (not $ debug_ui_ opts) $ update av (renderScreen a) | ||||||
|   k <- nextEvent av |   k <- nextEvent av | ||||||
|   d <- getCurrentDay |   d <- getCurrentDay | ||||||
|   case k of |   case k of | ||||||
|     EvResize x y                -> go $ resize' x y a |     EvResize x y                -> go $ resize' x y a | ||||||
|     EvKey (KChar 'l') [MCtrl]  -> refresh av >> go a{amsg=helpmsg} |     EvKey (KChar 'l') [MCtrl]  -> refresh av >> go a{amsg=helpmsg} | ||||||
|     EvKey (KChar 'b') []       -> go $ resetTrailAndEnter d BalanceScreen a |     -- EvKey (KChar 'b') []       -> go $ resetTrailAndEnter d BalanceScreen a | ||||||
|     EvKey (KChar 'r') []       -> go $ resetTrailAndEnter d RegisterScreen a |     -- EvKey (KChar 'r') []       -> go $ resetTrailAndEnter d RegisterScreen a | ||||||
|     EvKey (KChar 'p') []       -> go $ resetTrailAndEnter d PrintScreen a |     -- EvKey (KChar 'p') []       -> go $ resetTrailAndEnter d PrintScreen a | ||||||
|     EvKey KRight []             -> go $ drilldown d a |     EvKey KRight []             -> go $ drilldown d a | ||||||
|     EvKey KEnter []             -> go $ drilldown d a |     EvKey KEnter []             -> go $ drilldown d a | ||||||
|     EvKey KLeft  []             -> go $ backout d a |     EvKey KLeft  []             -> go $ backout d a | ||||||
| @ -329,13 +329,13 @@ currentTransaction a@AppState{ajournal=j,abuf=buf} = ptransaction p | |||||||
|     where |     where | ||||||
|       p = headDef nullposting $ filter ismatch $ journalPostings j |       p = headDef nullposting $ filter ismatch $ journalPostings j | ||||||
|       ismatch p = postingDate p == parsedate (take 10 datedesc) |       ismatch p = postingDate p == parsedate (take 10 datedesc) | ||||||
|                   && take 70 (showPostingWithBalanceForVty p nullmixedamt) == (datedesc ++ acctamt) |                   && take 70 (showPostingWithBalanceForUI p nullmixedamt) == (datedesc ++ acctamt) | ||||||
|       datedesc = take 32 $ fromMaybe "" $ find (not . (" " `isPrefixOf`)) $ headDef "" rest : reverse above |       datedesc = take 32 $ fromMaybe "" $ find (not . (" " `isPrefixOf`)) $ headDef "" rest : reverse above | ||||||
|       acctamt = drop 32 $ headDef "" rest |       acctamt = drop 32 $ headDef "" rest | ||||||
|       (above,rest) = splitAt y buf |       (above,rest) = splitAt y buf | ||||||
|       y = posY a |       y = posY a | ||||||
| 
 | 
 | ||||||
| showPostingWithBalanceForVty p b = | showPostingWithBalanceForUI p b = | ||||||
|   postingsReportItemAsText defcliopts $ |   postingsReportItemAsText defcliopts $ | ||||||
|   mkpostingsReportItem False False PrimaryDate Nothing p b |   mkpostingsReportItem False False PrimaryDate Nothing p b | ||||||
| 
 | 
 | ||||||
| @ -395,7 +395,9 @@ renderStatus w = string statusattr . take w . (++ repeat ' ') | |||||||
| 
 | 
 | ||||||
| -- the all-important theming engine! | -- the all-important theming engine! | ||||||
| 
 | 
 | ||||||
| theme = Restrained | -- theme = Restrained | ||||||
|  | theme = Colorful | ||||||
|  | -- theme = Blood | ||||||
| 
 | 
 | ||||||
| data UITheme = Restrained | Colorful | Blood | data UITheme = Restrained | Colorful | Blood | ||||||
| 
 | 
 | ||||||
| @ -3,7 +3,7 @@ | |||||||
| 
 | 
 | ||||||
| -} | -} | ||||||
| 
 | 
 | ||||||
| module Hledger.Vty.Options | module Hledger.UI.Options | ||||||
| where | where | ||||||
| import System.Console.CmdArgs | import System.Console.CmdArgs | ||||||
| import System.Console.CmdArgs.Explicit | import System.Console.CmdArgs.Explicit | ||||||
| @ -11,7 +11,7 @@ import System.Console.CmdArgs.Explicit | |||||||
| import Hledger.Cli hiding (progname,version,prognameandversion) | import Hledger.Cli hiding (progname,version,prognameandversion) | ||||||
| 
 | 
 | ||||||
| progname, version :: String | progname, version :: String | ||||||
| progname = "hledger-vty" | progname = "hledger-ui" | ||||||
| #ifdef VERSION | #ifdef VERSION | ||||||
| version = VERSION | version = VERSION | ||||||
| #else | #else | ||||||
| @ -20,16 +20,16 @@ version = "" | |||||||
| prognameandversion :: String | prognameandversion :: String | ||||||
| prognameandversion = progname ++ " " ++ version :: String | prognameandversion = progname ++ " " ++ version :: String | ||||||
| 
 | 
 | ||||||
| vtyflags = [ | uiflags = [ | ||||||
|   flagNone ["debug-vty"]  (\opts -> setboolopt "rules-file" opts) "run with no terminal output, showing console" |   flagNone ["debug-ui"]  (\opts -> setboolopt "rules-file" opts) "run with no terminal output, showing console" | ||||||
|  ] |  ] | ||||||
| 
 | 
 | ||||||
| --vtymode :: Mode [([Char], [Char])] | --uimode :: Mode [([Char], [Char])] | ||||||
| vtymode =  (mode "hledger-vty" [("command","vty")] | uimode =  (mode "hledger-ui" [("command","ui")] | ||||||
|             "browse accounts, postings and entries in a full-window curses interface" |             "browse accounts, postings and entries in a full-window curses interface" | ||||||
|             (argsFlag "[PATTERNS]") []){ |             (argsFlag "[PATTERNS]") []){ | ||||||
|               modeGroupFlags = Group { |               modeGroupFlags = Group { | ||||||
|                                 groupUnnamed = vtyflags |                                 groupUnnamed = uiflags | ||||||
|                                ,groupHidden = [] |                                ,groupHidden = [] | ||||||
|                                ,groupNamed = [(generalflagsgroup1)] |                                ,groupNamed = [(generalflagsgroup1)] | ||||||
|                                } |                                } | ||||||
| @ -38,31 +38,31 @@ vtymode =  (mode "hledger-vty" [("command","vty")] | |||||||
|                  ] |                  ] | ||||||
|            } |            } | ||||||
| 
 | 
 | ||||||
| -- hledger-vty options, used in hledger-vty and above | -- hledger-ui options, used in hledger-ui and above | ||||||
| data VtyOpts = VtyOpts { | data UIOpts = UIOpts { | ||||||
|      debug_vty_ :: Bool |      debug_ui_ :: Bool | ||||||
|     ,cliopts_   :: CliOpts |     ,cliopts_   :: CliOpts | ||||||
|  } deriving (Show) |  } deriving (Show) | ||||||
| 
 | 
 | ||||||
| defvtyopts = VtyOpts | defuiopts = UIOpts | ||||||
|     def |     def | ||||||
|     def |     def | ||||||
| 
 | 
 | ||||||
| -- instance Default CliOpts where def = defcliopts | -- instance Default CliOpts where def = defcliopts | ||||||
| 
 | 
 | ||||||
| toVtyOpts :: RawOpts -> IO VtyOpts | toUIOpts :: RawOpts -> IO UIOpts | ||||||
| toVtyOpts rawopts = do | toUIOpts rawopts = do | ||||||
|   cliopts <- rawOptsToCliOpts rawopts |   cliopts <- rawOptsToCliOpts rawopts | ||||||
|   return defvtyopts { |   return defuiopts { | ||||||
|               debug_vty_ = boolopt "debug-vty" rawopts |               debug_ui_ = boolopt "debug-ui" rawopts | ||||||
|              ,cliopts_   = cliopts |              ,cliopts_   = cliopts | ||||||
|              } |              } | ||||||
| 
 | 
 | ||||||
| checkVtyOpts :: VtyOpts -> IO VtyOpts | checkUIOpts :: UIOpts -> IO UIOpts | ||||||
| checkVtyOpts opts = do | checkUIOpts opts = do | ||||||
|   checkCliOpts $ cliopts_ opts |   checkCliOpts $ cliopts_ opts | ||||||
|   return opts |   return opts | ||||||
| 
 | 
 | ||||||
| getHledgerVtyOpts :: IO VtyOpts | getHledgerUIOpts :: IO UIOpts | ||||||
| getHledgerVtyOpts = processArgs vtymode >>= return . decodeRawOpts >>= toVtyOpts >>= checkVtyOpts | getHledgerUIOpts = processArgs uimode >>= return . decodeRawOpts >>= toUIOpts >>= checkUIOpts | ||||||
| 
 | 
 | ||||||
							
								
								
									
										4
									
								
								hledger-ui/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								hledger-ui/README
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | A curses-style console interface for the hledger accounting tool. | ||||||
|  | hledger-vty was revived in 2015 to become this package. | ||||||
|  | It allows browsing the balance, register and print reports with cursor keys and scrolling. | ||||||
|  | 
 | ||||||
| @ -1,4 +1,4 @@ | |||||||
| name:           hledger-vty | name:           hledger-ui | ||||||
| version: 0.26.98 | version: 0.26.98 | ||||||
| category:       Finance | category:       Finance | ||||||
| synopsis:       A curses-style console interface for the hledger accounting tool. | synopsis:       A curses-style console interface for the hledger accounting tool. | ||||||
| @ -24,18 +24,20 @@ build-type:     Simple | |||||||
| -- data-files: | -- data-files: | ||||||
| extra-tmp-files: | extra-tmp-files: | ||||||
| extra-source-files:  | extra-source-files:  | ||||||
|  |                     CHANGES | ||||||
|  |                     README | ||||||
| 
 | 
 | ||||||
| source-repository head | source-repository head | ||||||
|   type:     darcs |   type:     darcs | ||||||
|   location: http://joyful.com/repos/hledger |   location: http://joyful.com/repos/hledger | ||||||
| 
 | 
 | ||||||
| executable hledger-vty | executable hledger-ui | ||||||
|   main-is:        hledger-vty.hs |   main-is:        hledger-ui.hs | ||||||
|   ghc-options:    -threaded -W |   ghc-options:    -threaded -W | ||||||
|   other-modules: |   other-modules: | ||||||
|                   Hledger.Vty |                   Hledger.UI | ||||||
|                   Hledger.Vty.Main |                   Hledger.UI.Main | ||||||
|                   Hledger.Vty.Options |                   Hledger.UI.Options | ||||||
|   build-depends: |   build-depends: | ||||||
|                   hledger == 0.26.98 |                   hledger == 0.26.98 | ||||||
|                  ,hledger-lib == 0.26.98 |                  ,hledger-lib == 0.26.98 | ||||||
| @ -56,4 +58,4 @@ executable hledger-vty | |||||||
|                  -- ,split == 0.1.* |                  -- ,split == 0.1.* | ||||||
|                  ,time |                  ,time | ||||||
|                  -- ,utf8-string >= 0.3.5 && < 0.4 |                  -- ,utf8-string >= 0.3.5 && < 0.4 | ||||||
|                  ,vty >= 5.2 && < 5.3 |                  ,vty >= 5.2 && < 5.4 | ||||||
| @ -1,2 +1,2 @@ | |||||||
| #!/usr/bin/env runhaskell | #!/usr/bin/env runhaskell | ||||||
| import Hledger.Vty (main) | import Hledger.UI (main) | ||||||
| @ -1,7 +1,9 @@ | |||||||
| packages: | packages: | ||||||
| - hledger-lib | - hledger-lib | ||||||
| - hledger | - hledger | ||||||
|  | - hledger-ui | ||||||
| - hledger-web | - hledger-web | ||||||
| flags: {} | flags: {} | ||||||
| resolver: lts-3.0 | resolver: lts-3.0 | ||||||
| extra-deps: | extra-deps: | ||||||
|  | - vty-5.3.1 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user