<commit_before>-- required imports
import XMonad
import Data.Monoid
import System.Exit
import qualified XMonad.StackSet as W
import qualified Data.Map        as M

-- optional imports
import Data.Maybe (isJust, isNothing)
import XMonad.Actions.Warp -- for mouse warping
import XMonad.Actions.GridSelect -- for selecting workspaces, etc. from a 2D, pretty grid
import XMonad.Actions.NoBorders -- for toggling borders on a per-window basis
import XMonad.Actions.CycleWS -- for workspace-to-workspace navigation
import XMonad.Hooks.ManageHelpers -- for doCenterFloat

import XMonad.Layout.NoBorders -- enable borderless layouts
import XMonad.Layout.Circle -- circle layout
import XMonad.Layout.LayoutHints -- for (among other things) removing GVim's dead borders automatically

import XMonad.Util.WorkspaceCompare (getSortByIndex)
import System.Posix.Unistd -- for getting hostname
import XMonad.Hooks.EwmhDesktops -- for _NET_WINDOW_WINDOW (emacs + SCIM bridge)

import System.Random
import Data.Array.IO
import Control.Monad

-- The preferred terminal program, which is used in a binding below and by
-- certain contrib modules.
--
myTerminal      = "urxvt"

myFocusFollowsMouse = True
myBorderWidth   = 1

-- modMask lets you specify which modkey you want to use. The default
-- is mod1Mask ("left alt").  You may also consider using mod3Mask
-- ("right alt"), which does not conflict with emacs keybindings. The
-- "windows key" is usually mod4Mask.
-- You can double-check which key is which modmask by running 'xmodmap'
myModMask       = mod3Mask -- use the CAPSLOCK key
altMask         = mod1Mask -- alias "altMask" for left alt key

-- The mask for the numlock key. Numlock status is "masked" from the
-- current modifier status, so the keybindings will work with numlock on or
-- off. You may need to change this on some systems.
--
-- You can find the numlock modifier by running "xmodmap" and looking for a
-- modifier with Num_Lock bound to it:
--
-- > $ xmodmap | grep Num
-- > mod2        Num_Lock (0x4d)
--
-- Set numlockMask = 0 if you don't have a numlock key, or want to treat
-- numlock status separately.
--
myNumlockMask   = mod2Mask

data MyWSGroup = Work | Net | Misc | Music | Net2 | Sys
    deriving (Eq, Ord, Enum, Show)

_MYWSGROUPS = [Net ..] -- list of all MyWSGroup

-- Use an association list for more flexible custom workspace manipulation.
--
-- The fact that we do not necessarily follow the ordering of the MYWSGroup data type allows for
-- maximum flexibility: we can either directly choose, via xK_1 ... xK_F12 keys what we want (like
-- we did in the past), but at the same time we can also choose to navigate via the ordering in
-- MyWSGroup via the custom diffGrpWS function.
myWorkspaceGroups :: [(WorkspaceId, MyWSGroup)]
myWorkspaceGroups = [ ("1",   Work)
                    , ("2",   Work)
                    , ("3",   Work)
                    , ("4",   Work)
                    , ("5",   Work)
                    , ("6",   Work)
                    , ("7",   Work)
                    , ("8",   Net)
                    , ("9",   Net)
                    , ("0",   Music) -- ncmpcpp, terminal named "mplayer" (used when streaming music on LAN)
                    , ("F1",  Misc)
                    , ("F2",  Misc)
                    , ("F3",  Misc)
                    , ("F4",  Misc)
                    , ("F5",  Misc)
                    , ("F6",  Misc)
                    , ("F7",  Misc)
                    , ("F8",  Misc)
                    , ("F9",  Net2) -- IRC
                    , ("F10", Net2)
                    , ("F11", Sys)
                    , ("F12", Sys)
                    ]

myWorkspaces = map fst myWorkspaceGroups -- 1..9, 0, F1-F12

myNormalBorderColor  = "#000000"
myFocusedBorderColor = "#ffffff"

-- terminals (various different color themes)
term1 = "~/syscfg/script/sys/terms/wb.sh"
term2 = "~/syscfg/script/sys/terms/bw.sh"
term3 = "~/syscfg/script/sys/terms/wB.sh"

orgIntraday = " -name floatme -e ~/prog/timeflux/src/term.sh intraday ~/org/life.org @@@"
orgPlans5w = " -name floatme -e ~/prog/timeflux/src/term.sh plans5w ~/org/life.org @@@"
orgGoals10w = " -name floatme -e ~/prog/timeflux/src/term.sh goals10w ~/org/life.org @@@"
orgLeftToday = " -name floatme -e ~/prog/timeflux/src/term.sh lefttoday ~/org/life.org @@@"

myKeys :: String -> XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
myKeys hostname conf@(XConfig {XMonad.modMask = modm}) = M.fromList $

    -- launch a terminal
    [ ((modm .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)

    -- close focused window
    , ((modm,               xK_d     ), kill)

     -- Rotate through the available layout algorithms
    , ((modm,               xK_space ), sendMessage NextLayout)

    --  Reset the layouts on the current workspace to default
    , ((modm .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf)

    -- Resize viewed windows to the correct size
    , ((modm,               xK_n     ), refresh)

    -- Move focus to the next window
    , ((modm,               xK_Tab   ), windows W.focusDown)

    -- Move focus to the next window
    , ((modm,               xK_j     ), windows W.focusDown)

    -- Move focus to the previous window
    , ((modm,               xK_k     ), windows W.focusUp  )

    -- Move focus to the master window
    , ((modm,               xK_m     ), windows W.focusMaster  )

    -- Swap the focused window and the master window
    , ((modm,               xK_Return), windows W.swapMaster)

    -- Swap the focused window with the next window
    , ((modm .|. shiftMask, xK_j     ), windows W.swapDown  )

    -- Swap the focused window with the previous window
    , ((modm .|. shiftMask, xK_k     ), windows W.swapUp    )

    -- Shrink the master area
    , ((modm,               xK_w     ), sendMessage Shrink)

    -- Expand the master area
    , ((modm,               xK_e     ), sendMessage Expand)

    -- Push window back into tiling
    , ((modm,               xK_t     ), withFocused $ windows . W.sink)

    -- Increment the number of windows in the master area
    , ((modm              , xK_comma ), sendMessage (IncMasterN 1))

    -- Deincrement the number of windows in the master area
    , ((modm              , xK_period), sendMessage (IncMasterN (-1)))

    -- Quit xmonad
    , ((modm .|. controlMask, xK_Escape     ), io (exitWith ExitSuccess))

    -- Restart xmonad
    , ((modm .|. altMask,   xK_Escape     ), spawn "xmonad --recompile; xmonad --restart")

    -- CUSTOM KEYBINDINGS HERE --
    , ((mod4Mask              , xK_1     ), spawn (term1 ++ orgIntraday))
    , ((mod4Mask              , xK_2     ), spawn (term1 ++ orgPlans5w))
    , ((mod4Mask              , xK_3     ), spawn (term1 ++ orgGoals10w))
    , ((mod4Mask              , xK_9     ), spawn (term1 ++ orgLeftToday))
    , ((mod4Mask              , xK_0     ), spawn "emacsclient -c /home/listdata/org/life.org")
    , ((mod4Mask              , xK_c     ), spawn "galculator")
    , ((mod4Mask .|. shiftMask, xK_c     ), spawn "gcalctool")
    , ((mod4Mask              , xK_d     ), spawn "amule")
    , ((mod4Mask              , xK_e     ), spawn (term1 ++ " -e mutt"))
    , ((mod4Mask .|. shiftMask, xK_f     ), spawn "gnucash")
    , ((mod4Mask              , xK_h     ), spawn (term2 ++ " -e ncmpcpp"))
    , ((mod4Mask .|. shiftMask, xK_h     ), spawn (term2 ++ " -e mplayer -ao oss -softvol -volume 100 -volstep 1 -demuxer ogg -prefer-ipv4 http://192.168.0.110:8000/mpd.ogg"))
    , ((mod4Mask              , xK_i     ), spawn "gimp")
    , ((mod4Mask              , xK_m     ), spawn "blender")
    , ((mod4Mask              , xK_n     ), spawn "firefox")
    , ((mod4Mask .|. shiftMask, xK_n     ), io sitesRand >>= spawn . ("firefox " ++))
    , ((mod4Mask              , xK_w     ), spawn "soffice")
    , ((mod4Mask              , xK_x     ), spawn term1)
    , ((mod4Mask .|. shiftMask, xK_x     ), spawn term3)
    , ((mod4Mask              , xK_z     ), spawn term2)
    -- ncmpcpp (mpd) controls
    , ((mod4Mask .|. controlMask, xK_o     ), spawn "ncmpcpp toggle")
    , ((mod4Mask .|. controlMask, xK_h     ), spawn "ncmpcpp stop; ncmpcpp play") -- "reset" current song to beginning
    , ((mod4Mask .|. controlMask, xK_j     ), spawn "ncmpcpp next")
    , ((mod4Mask .|. controlMask, xK_k     ), spawn "ncmpcpp prev")
    , ((mod4Mask .|. controlMask, xK_l     ), spawn "ncmpcpp stop")
    , ((mod4Mask .|. controlMask, xK_semicolon ), spawn "ncmpcpp play")
    -- change keyboard layouts
    , ((modm              , xK_Escape), spawn "/home/listdata/syscfg/script/sys/layout_switch.sh")
    -- toggle borders
    , ((modm              , xK_b ),   withFocused toggleBorder)
    -- gridselect
    , ((modm              , xK_f), goToSelected defaultGSConfig)
    -- volume controls
    , ((modm              , xK_backslash ), spawn "amixer -q set Master toggle")
    , ((modm              , xK_minus     ), spawn "amixer -q set Master 1dB- unmute")
    , ((modm              , xK_equal     ), spawn "amixer -q set Master 1.5dB+ unmute")
    -- screen brightness toggle
    , ((modm .|. shiftMask, xK_backslash ), spawn "sudo brightness") -- toggle brightness (100% or 0%)
    , ((modm .|. shiftMask, xK_minus ), cpufreqSet "powersave" hostname)
    , ((modm .|. shiftMask, xK_equal ), cpufreqSet "ondemand" hostname)
    , ((modm .|. shiftMask, xK_BackSpace ), cpufreqSet "performance" hostname)
    -- move mouse away to bottom-right of currently focused window
    , ((modm              , xK_BackSpace), warpToWindow 1 1)
    ]
    ++

    -- mod-[1..9, 0, F1-F12], Switch to workspace N
    -- mod-shift-[1..9, 0, F1-F12], Move focused window to workspace N
    [((m .|. modm, k), windows $ f i)
        | (i, k) <- zip (XMonad.workspaces conf) ([xK_1..xK_9] ++ [xK_0] ++ [xK_F1..xK_F11] ++ [xK_F12])
        , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
    ++

    [
      ((modm .|. altMask,   xK_j),              moveTo Next nonEmptyGrpWS) -- go to next non-empty WS, in current Group
    , ((modm .|. altMask,   xK_k),              moveTo Prev nonEmptyGrpWS) -- go to prev non-empty WS, in current Group
    , ((modm .|. altMask,   xK_l),              moveTo Next $ diffGrpWS 1)     -- go to next WS Group
    , ((modm .|. altMask,   xK_h),              moveTo Next $ diffGrpWS (-1))  -- go to previous WS Group (the "moveTo Next" part here ensures that, after getting our desired new WSGroup, that we always display the top WS of that Group
    , ((modm .|. altMask,   xK_o),              action_o)    -- go to next hidden empty WS (if possible), in current Group, and spawn a new "window" there (depends on group)
    , ((modm, xK_n),                            moveTo Next $ nonEmptyWSExceptGrps [Net2, Sys])    -- go to any non-empty WS, except those WS belonging to the given WS Groups (for making sure that our "desk" is clean before we log off/shutdown)
    , ((modm .|. altMask .|. shiftMask, xK_j),  shiftTo Next grpWS) -- move window to next WS, in current Group
    , ((modm .|. altMask .|. shiftMask, xK_k),  shiftTo Prev grpWS) -- move window to prev WS, in current Group
    , ((modm .|. altMask .|. shiftMask, xK_l),  shiftTo Next $ diffGrpWS 1) -- move window to next WS group
    , ((modm .|. altMask .|. shiftMask, xK_h),  shiftTo Next $ diffGrpWS (-1)) -- move window to prev WS group
    , ((modm, xK_semicolon),                    toggleWS) -- go to WS displayed previously
    , ((modm .|. altMask, xK_BackSpace),        resetScreensToWSTops) -- reset each Xinerama screen so that they point to the heads of each group
    ]

    ++

    --
    -- mod-{h,l}, Switch to prev/next Xinerama screens
    -- mod-shift-{h,l}, Move client to prev/next screen
    --
    [((m .|. modm, key), (screenWorkspace =<< sc) >>= flip whenJust (windows . f))
        | (key, sc) <- [(xK_h, screenBy (-1)),(xK_l, screenBy 1)]
        , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]

cpufreqSet :: String -> String -> X ()
cpufreqSet governor hostname = case hostname of
    "exelion"   -> mapM_ (spawn . cpu) [0..3]
    "aether"    -> mapM_ (spawn . cpu) [0..1]
    "luxion"    -> mapM_ (spawn . cpu) [0]
    _ -> return ()
    where
        cpu n = "sudo cpufreq-set -c " ++ show n ++ " -g " ++ governor
<commit_msg>xmonad: add mpc bindings (mpd seek support)<commit_after>-- required imports
import XMonad
import Data.Monoid
import System.Exit
import qualified XMonad.StackSet as W
import qualified Data.Map        as M

-- optional imports
import Data.Maybe (isJust, isNothing)
import XMonad.Actions.Warp -- for mouse warping
import XMonad.Actions.GridSelect -- for selecting workspaces, etc. from a 2D, pretty grid
import XMonad.Actions.NoBorders -- for toggling borders on a per-window basis
import XMonad.Actions.CycleWS -- for workspace-to-workspace navigation
import XMonad.Hooks.ManageHelpers -- for doCenterFloat

import XMonad.Layout.NoBorders -- enable borderless layouts
import XMonad.Layout.Circle -- circle layout
import XMonad.Layout.LayoutHints -- for (among other things) removing GVim's dead borders automatically

import XMonad.Util.WorkspaceCompare (getSortByIndex)
import System.Posix.Unistd -- for getting hostname
import XMonad.Hooks.EwmhDesktops -- for _NET_WINDOW_WINDOW (emacs + SCIM bridge)

import System.Random
import Data.Array.IO
import Control.Monad

-- The preferred terminal program, which is used in a binding below and by
-- certain contrib modules.
--
myTerminal      = "urxvt"

myFocusFollowsMouse = True
myBorderWidth   = 1

-- modMask lets you specify which modkey you want to use. The default
-- is mod1Mask ("left alt").  You may also consider using mod3Mask
-- ("right alt"), which does not conflict with emacs keybindings. The
-- "windows key" is usually mod4Mask.
-- You can double-check which key is which modmask by running 'xmodmap'
myModMask       = mod3Mask -- use the CAPSLOCK key
altMask         = mod1Mask -- alias "altMask" for left alt key

-- The mask for the numlock key. Numlock status is "masked" from the
-- current modifier status, so the keybindings will work with numlock on or
-- off. You may need to change this on some systems.
--
-- You can find the numlock modifier by running "xmodmap" and looking for a
-- modifier with Num_Lock bound to it:
--
-- > $ xmodmap | grep Num
-- > mod2        Num_Lock (0x4d)
--
-- Set numlockMask = 0 if you don't have a numlock key, or want to treat
-- numlock status separately.
--
myNumlockMask   = mod2Mask

data MyWSGroup = Work | Net | Misc | Music | Net2 | Sys
    deriving (Eq, Ord, Enum, Show)

_MYWSGROUPS = [Net ..] -- list of all MyWSGroup

-- Use an association list for more flexible custom workspace manipulation.
--
-- The fact that we do not necessarily follow the ordering of the MYWSGroup data type allows for
-- maximum flexibility: we can either directly choose, via xK_1 ... xK_F12 keys what we want (like
-- we did in the past), but at the same time we can also choose to navigate via the ordering in
-- MyWSGroup via the custom diffGrpWS function.
myWorkspaceGroups :: [(WorkspaceId, MyWSGroup)]
myWorkspaceGroups = [ ("1",   Work)
                    , ("2",   Work)
                    , ("3",   Work)
                    , ("4",   Work)
                    , ("5",   Work)
                    , ("6",   Work)
                    , ("7",   Work)
                    , ("8",   Net)
                    , ("9",   Net)
                    , ("0",   Music) -- ncmpcpp, terminal named "mplayer" (used when streaming music on LAN)
                    , ("F1",  Misc)
                    , ("F2",  Misc)
                    , ("F3",  Misc)
                    , ("F4",  Misc)
                    , ("F5",  Misc)
                    , ("F6",  Misc)
                    , ("F7",  Misc)
                    , ("F8",  Misc)
                    , ("F9",  Net2) -- IRC
                    , ("F10", Net2)
                    , ("F11", Sys)
                    , ("F12", Sys)
                    ]

myWorkspaces = map fst myWorkspaceGroups -- 1..9, 0, F1-F12

myNormalBorderColor  = "#000000"
myFocusedBorderColor = "#ffffff"

-- terminals (various different color themes)
term1 = "~/syscfg/script/sys/terms/wb.sh"
term2 = "~/syscfg/script/sys/terms/bw.sh"
term3 = "~/syscfg/script/sys/terms/wB.sh"

orgIntraday = " -name floatme -e ~/prog/timeflux/src/term.sh intraday ~/org/life.org @@@"
orgPlans5w = " -name floatme -e ~/prog/timeflux/src/term.sh plans5w ~/org/life.org @@@"
orgGoals10w = " -name floatme -e ~/prog/timeflux/src/term.sh goals10w ~/org/life.org @@@"
orgLeftToday = " -name floatme -e ~/prog/timeflux/src/term.sh lefttoday ~/org/life.org @@@"

myKeys :: String -> XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
myKeys hostname conf@(XConfig {XMonad.modMask = modm}) = M.fromList $

    -- launch a terminal
    [ ((modm .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)

    -- close focused window
    , ((modm,               xK_d     ), kill)

     -- Rotate through the available layout algorithms
    , ((modm,               xK_space ), sendMessage NextLayout)

    --  Reset the layouts on the current workspace to default
    , ((modm .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf)

    -- Resize viewed windows to the correct size
    , ((modm,               xK_n     ), refresh)

    -- Move focus to the next window
    , ((modm,               xK_Tab   ), windows W.focusDown)

    -- Move focus to the next window
    , ((modm,               xK_j     ), windows W.focusDown)

    -- Move focus to the previous window
    , ((modm,               xK_k     ), windows W.focusUp  )

    -- Move focus to the master window
    , ((modm,               xK_m     ), windows W.focusMaster  )

    -- Swap the focused window and the master window
    , ((modm,               xK_Return), windows W.swapMaster)

    -- Swap the focused window with the next window
    , ((modm .|. shiftMask, xK_j     ), windows W.swapDown  )

    -- Swap the focused window with the previous window
    , ((modm .|. shiftMask, xK_k     ), windows W.swapUp    )

    -- Shrink the master area
    , ((modm,               xK_w     ), sendMessage Shrink)

    -- Expand the master area
    , ((modm,               xK_e     ), sendMessage Expand)

    -- Push window back into tiling
    , ((modm,               xK_t     ), withFocused $ windows . W.sink)

    -- Increment the number of windows in the master area
    , ((modm              , xK_comma ), sendMessage (IncMasterN 1))

    -- Deincrement the number of windows in the master area
    , ((modm              , xK_period), sendMessage (IncMasterN (-1)))

    -- Quit xmonad
    , ((modm .|. controlMask, xK_Escape     ), io (exitWith ExitSuccess))

    -- Restart xmonad
    , ((modm .|. altMask,   xK_Escape     ), spawn "xmonad --recompile; xmonad --restart")

    -- CUSTOM KEYBINDINGS HERE --
    , ((mod4Mask              , xK_1     ), spawn (term1 ++ orgIntraday))
    , ((mod4Mask              , xK_2     ), spawn (term1 ++ orgPlans5w))
    , ((mod4Mask              , xK_3     ), spawn (term1 ++ orgGoals10w))
    , ((mod4Mask              , xK_9     ), spawn (term1 ++ orgLeftToday))
    , ((mod4Mask              , xK_0     ), spawn "emacsclient -c /home/listdata/org/life.org")
    , ((mod4Mask              , xK_c     ), spawn "galculator")
    , ((mod4Mask .|. shiftMask, xK_c     ), spawn "gcalctool")
    , ((mod4Mask              , xK_d     ), spawn "amule")
    , ((mod4Mask              , xK_e     ), spawn (term1 ++ " -e mutt"))
    , ((mod4Mask .|. shiftMask, xK_f     ), spawn "gnucash")
    , ((mod4Mask              , xK_h     ), spawn (term2 ++ " -e ncmpcpp"))
    , ((mod4Mask .|. shiftMask, xK_h     ), spawn (term2 ++ " -e mplayer -ao oss -softvol -volume 100 -volstep 1 -demuxer ogg -prefer-ipv4 http://192.168.0.110:8000/mpd.ogg"))
    , ((mod4Mask              , xK_i     ), spawn "gimp")
    , ((mod4Mask              , xK_m     ), spawn "blender")
    , ((mod4Mask              , xK_n     ), spawn "firefox")
    , ((mod4Mask .|. shiftMask, xK_n     ), io sitesRand >>= spawn . ("firefox " ++))
    , ((mod4Mask              , xK_w     ), spawn "soffice")
    , ((mod4Mask              , xK_x     ), spawn term1)
    , ((mod4Mask .|. shiftMask, xK_x     ), spawn term3)
    , ((mod4Mask              , xK_z     ), spawn term2)
    -- ncmpcpp (mpd) controls
    , ((mod4Mask .|. controlMask, xK_i                   ), spawn "ncmpcpp stop")
    , ((mod4Mask .|. controlMask .|. shiftMask, xK_i     ), spawn "ncmpcpp stop; ncmpcpp play") -- "reset" current song to beginning
    , ((mod4Mask .|. controlMask, xK_o                   ), spawn "ncmpcpp toggle")
    , ((mod4Mask .|. controlMask, xK_h                   ), spawn $ mpcSeek hostname (-4))
    , ((mod4Mask .|. controlMask .|. shiftMask, xK_h     ), spawn $ mpcSeek hostname (-16))
    , ((mod4Mask .|. controlMask, xK_j                   ), spawn "ncmpcpp next")
    , ((mod4Mask .|. controlMask, xK_k                   ), spawn "ncmpcpp prev")
    , ((mod4Mask .|. controlMask, xK_l                   ), spawn $ mpcSeek hostname 4)
    , ((mod4Mask .|. controlMask .|. shiftMask, xK_l     ), spawn $ mpcSeek hostname 16)
    , ((mod4Mask .|. controlMask, xK_semicolon           ), spawn "ncmpcpp play")
    -- change keyboard layouts
    , ((modm              , xK_Escape), spawn "/home/listdata/syscfg/script/sys/layout_switch.sh")
    -- toggle borders
    , ((modm              , xK_b ),   withFocused toggleBorder)
    -- gridselect
    , ((modm              , xK_f), goToSelected defaultGSConfig)
    -- volume controls
    , ((modm              , xK_backslash ), spawn "amixer -q set Master toggle")
    , ((modm              , xK_minus     ), spawn "amixer -q set Master 1dB- unmute")
    , ((modm              , xK_equal     ), spawn "amixer -q set Master 1.5dB+ unmute")
    -- screen brightness toggle
    , ((modm .|. shiftMask, xK_backslash ), spawn "sudo brightness") -- toggle brightness (100% or 0%)
    , ((modm .|. shiftMask, xK_minus ), cpufreqSet "powersave" hostname)
    , ((modm .|. shiftMask, xK_equal ), cpufreqSet "ondemand" hostname)
    , ((modm .|. shiftMask, xK_BackSpace ), cpufreqSet "performance" hostname)
    -- move mouse away to bottom-right of currently focused window
    , ((modm              , xK_BackSpace), warpToWindow 1 1)
    ]
    ++

    -- mod-[1..9, 0, F1-F12], Switch to workspace N
    -- mod-shift-[1..9, 0, F1-F12], Move focused window to workspace N
    [((m .|. modm, k), windows $ f i)
        | (i, k) <- zip (XMonad.workspaces conf) ([xK_1..xK_9] ++ [xK_0] ++ [xK_F1..xK_F11] ++ [xK_F12])
        , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
    ++

    [
      ((modm .|. altMask,   xK_j),              moveTo Next nonEmptyGrpWS) -- go to next non-empty WS, in current Group
    , ((modm .|. altMask,   xK_k),              moveTo Prev nonEmptyGrpWS) -- go to prev non-empty WS, in current Group
    , ((modm .|. altMask,   xK_l),              moveTo Next $ diffGrpWS 1)     -- go to next WS Group
    , ((modm .|. altMask,   xK_h),              moveTo Next $ diffGrpWS (-1))  -- go to previous WS Group (the "moveTo Next" part here ensures that, after getting our desired new WSGroup, that we always display the top WS of that Group
    , ((modm .|. altMask,   xK_o),              action_o)    -- go to next hidden empty WS (if possible), in current Group, and spawn a new "window" there (depends on group)
    , ((modm, xK_n),                            moveTo Next $ nonEmptyWSExceptGrps [Net2, Sys])    -- go to any non-empty WS, except those WS belonging to the given WS Groups (for making sure that our "desk" is clean before we log off/shutdown)
    , ((modm .|. altMask .|. shiftMask, xK_j),  shiftTo Next grpWS) -- move window to next WS, in current Group
    , ((modm .|. altMask .|. shiftMask, xK_k),  shiftTo Prev grpWS) -- move window to prev WS, in current Group
    , ((modm .|. altMask .|. shiftMask, xK_l),  shiftTo Next $ diffGrpWS 1) -- move window to next WS group
    , ((modm .|. altMask .|. shiftMask, xK_h),  shiftTo Next $ diffGrpWS (-1)) -- move window to prev WS group
    , ((modm, xK_semicolon),                    toggleWS) -- go to WS displayed previously
    , ((modm .|. altMask, xK_BackSpace),        resetScreensToWSTops) -- reset each Xinerama screen so that they point to the heads of each group
    ]

    ++

    --
    -- mod-{h,l}, Switch to prev/next Xinerama screens
    -- mod-shift-{h,l}, Move client to prev/next screen
    --
    [((m .|. modm, key), (screenWorkspace =<< sc) >>= flip whenJust (windows . f))
        | (key, sc) <- [(xK_h, screenBy (-1)),(xK_l, screenBy 1)]
        , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]

mpcSeek :: String -> Int -> String
mpcSeek hostname sec = "mpc -h 192.168.0.110 -p " ++ port ++ " seek " ++ show' sec
    where
        port = case hostname of
            "exelion" -> "6600" -- alsa
            _ -> "6601" -- icecast
        show' n
            | n < 0 = show n
            | otherwise = '+':show n

cpufreqSet :: String -> String -> X ()
cpufreqSet governor hostname = case hostname of
    "exelion"   -> mapM_ (spawn . cpu) [0..3]
    "aether"    -> mapM_ (spawn . cpu) [0..1]
    "luxion"    -> mapM_ (spawn . cpu) [0]
    _ -> return ()
    where
        cpu n = "sudo cpufreq-set -c " ++ show n ++ " -g " ++ governor

{'fraction_non_alphanumeric': 0.13103230392544032, 'fraction_numerical': 0.014730274069978675, 'mean_word_length': 2.0531709669640703, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 3, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '608033', 'n_tokens_mistral': 8632, 'n_tokens_neox': 8222, 'n_words': 2563}