diff --git a/Makefile.am b/Makefile.am index 553b4e707444fbc9886542bbfb254ed7305bf61b..38f0e460aac5f6ff34ecd746363f7d64bb35fced 100644 --- a/Makefile.am +++ b/Makefile.am @@ -914,6 +914,7 @@ TEST_FILES = \ test/data/bdev-drbd-net-ip6.txt \ test/data/cert1.pem \ test/data/cert2.pem \ + test/data/instance-minor-pairing.txt \ test/data/ip-addr-show-dummy0.txt \ test/data/ip-addr-show-lo-ipv4.txt \ test/data/ip-addr-show-lo-ipv6.txt \ diff --git a/man/mon-collector.rst b/man/mon-collector.rst index 6260e2ea64e783c18b85e67be5ac951767b3ad7f..aea881200a8fad1c1d84f4553b27b2917173d7ac 100644 --- a/man/mon-collector.rst +++ b/man/mon-collector.rst @@ -33,10 +33,21 @@ COLLECTORS DRBD ~~~~ -| drbd [*status-file*] +| drbd [ [ **-s** | **\--drbd-status** ] = *status-file* ] [ [ **-p** | **\--drbd-pairing**] = *pairing-file* ] Collects the information about the version and status of the DRBD kernel module, and of the disks it is managing. -If *status-file* is specified, the status will be read from that file. -Otherwise, the collector will read it from /proc/drbd. +If *status-file* and *pairing-file* are specified, the status and the +instance-minor paring information will be read from those files. +Otherwise, the collector will read them, respectively, from /proc/drbd +and from the Confd server. + +The options that can be passed to the DRBD collector are as follows: + +-s *status-file*, \--drbd-status=*status-file* + Read the DRBD status from the specified file instead of /proc/drbd. + +-p *pairing-file*, \--drbd-pairing=*pairing-file* + Read the information about the pairing between instances and DRBD minors + from the specified file instead of asking the Confd servers for them. diff --git a/src/Ganeti/DataCollectors/CLI.hs b/src/Ganeti/DataCollectors/CLI.hs index b1289b3bc0459e6f39235eecf08ff293812270f1..c793078079ad69205e16322b73eb8a04925336c2 100644 --- a/src/Ganeti/DataCollectors/CLI.hs +++ b/src/Ganeti/DataCollectors/CLI.hs @@ -34,9 +34,14 @@ module Ganeti.DataCollectors.CLI , oShowHelp , oShowVer , oShowComp + , oDrbdPairing + , oDrbdStatus , genericOptions ) where +import System.Console.GetOpt + +import Ganeti.BasicTypes import Ganeti.Common as Common -- * Data types @@ -46,6 +51,10 @@ data Options = Options { optShowHelp :: Bool -- ^ Just show the help , optShowComp :: Bool -- ^ Just show the completion info , optShowVer :: Bool -- ^ Just show the program version + , optDrbdStatus :: Maybe FilePath -- ^ Path to the file containing DRBD + -- status information + , optDrbdPairing :: Maybe FilePath -- ^ Path to the file containing pairings + -- between instances and DRBD minors } deriving Show -- | Default values for the command line options. @@ -54,6 +63,8 @@ defaultOptions = Options { optShowHelp = False , optShowComp = False , optShowVer = False + , optDrbdStatus = Nothing + , optDrbdPairing = Nothing } -- | Abbreviation for the option type. @@ -68,6 +79,19 @@ instance StandardOptions Options where requestComp o = o { optShowComp = True } -- * Command line options +oDrbdPairing :: OptType +oDrbdPairing = + ( Option "p" ["drbd-pairing"] + (ReqArg (\ f o -> Ok o { optDrbdPairing = Just f}) "FILE") + "the FILE containing pairings between instances and DRBD minors", + OptComplFile) + +oDrbdStatus :: OptType +oDrbdStatus = + ( Option "s" ["drbd-status"] + (ReqArg (\ f o -> Ok o { optDrbdStatus = Just f }) "FILE") + "the DRBD status FILE", + OptComplFile) -- | Generic options. genericOptions :: [GenericOptType Options] diff --git a/src/Ganeti/DataCollectors/Drbd.hs b/src/Ganeti/DataCollectors/Drbd.hs index 8a9babcf13af7539e1320f97d19c992a96389410..0a3b6a31799f310190aa4bcd50bac5e383e31b7a 100644 --- a/src/Ganeti/DataCollectors/Drbd.hs +++ b/src/Ganeti/DataCollectors/Drbd.hs @@ -31,14 +31,20 @@ module Ganeti.DataCollectors.Drbd import qualified Control.Exception as E +import Control.Monad import Data.Attoparsec.Text.Lazy as A +import Data.Maybe import Data.Text.Lazy (pack, unpack) -import Text.JSON +import Network.BSD (getHostName) +import qualified Text.JSON as J import qualified Ganeti.BasicTypes as BT import qualified Ganeti.Constants as C import Ganeti.Block.Drbd.Parser(drbdStatusParser) +import Ganeti.Block.Drbd.Types(DrbdInstMinor) import Ganeti.Common +import Ganeti.Confd.Client +import Ganeti.Confd.Types import Ganeti.DataCollectors.CLI import Ganeti.Utils @@ -56,29 +62,55 @@ defaultCharNum :: Int defaultCharNum = 80*20 options :: IO [OptType] -options = return [] +options = + return + [ oDrbdStatus + , oDrbdPairing + ] -- | The list of arguments supported by the program. arguments :: [ArgCompletion] -arguments = [ArgCompletion OptComplFile 0 (Just 1)] +arguments = [ArgCompletion OptComplFile 0 (Just 0)] -- * Command line options +-- | Get information about the pairing of DRBD minors and Ganeti instances +-- on the current node. The information is taken from the Confd client +-- or, if a filename is specified, from a JSON encoded file (for testing +-- purposes). +getPairingInfo :: Maybe String -> IO (BT.Result [DrbdInstMinor]) +getPairingInfo Nothing = do + curNode <- getHostName + client <- getConfdClient + reply <- query client ReqNodeDrbd $ PlainQuery curNode + return $ + case fmap (J.readJSONs . confdReplyAnswer) reply of + Just (J.Ok instMinor) -> BT.Ok instMinor + Just (J.Error msg) -> BT.Bad msg + Nothing -> BT.Bad "No answer from the Confd server" +getPairingInfo (Just filename) = do + content <- readFile filename + return $ + case J.decode content of + J.Ok instMinor -> BT.Ok instMinor + J.Error msg -> BT.Bad msg + -- | Main function. main :: Options -> [String] -> IO () -main _ args = do - proc_drbd <- case args of - [ ] -> return defaultFile - [x] -> return x - _ -> exitErr $ "This program takes only one argument," ++ - " got '" ++ unwords args ++ "'" +main opts args = do + let proc_drbd = fromMaybe defaultFile $ optDrbdStatus opts + instMinor = optDrbdPairing opts + unless (null args) . exitErr $ "This program takes exactly zero" ++ + " arguments, got '" ++ unwords args ++ "'" contents <- ((E.try $ readFile proc_drbd) :: IO (Either IOError String)) >>= exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok + pairingResult <- getPairingInfo instMinor + pairing <- exitIfBad "Can't get pairing info" pairingResult output <- - case A.parse (drbdStatusParser []) $ pack contents of + case A.parse (drbdStatusParser pairing) $ pack contents of A.Fail unparsedText contexts errorMessage -> exitErr $ show (Prelude.take defaultCharNum $ unpack unparsedText) ++ "\n" ++ show contexts ++ "\n" ++ errorMessage - A.Done _ drbdStatus -> return $ encode drbdStatus + A.Done _ drbdStatus -> return $ J.encode drbdStatus putStrLn output diff --git a/test/data/instance-minor-pairing.txt b/test/data/instance-minor-pairing.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ffea33539cb28596ce90874f9ca9f2ecb6e3477 --- /dev/null +++ b/test/data/instance-minor-pairing.txt @@ -0,0 +1,2 @@ +[["machine1.example.com",0,"instance1.example.com","disk/0","secondary", +"machine2.example.com"]] diff --git a/test/hs/shelltests/htools-mon-collector.test b/test/hs/shelltests/htools-mon-collector.test index e0ab7a30904702793742c9b242d0f7c690722437..f9bf1c99cac84ff4b806ad63b150342cd376884e 100644 --- a/test/hs/shelltests/htools-mon-collector.test +++ b/test/hs/shelltests/htools-mon-collector.test @@ -23,30 +23,27 @@ >>>= 0 # 3. Test that the drbd collector fails parsing /dev/null -./test/hs/hpc-mon-collector drbd /dev/null ->>>2 -Error: "" -[] -Failed reading: versionInfo +./test/hs/hpc-mon-collector drbd --drbd-status=/dev/null --drbd-pairing=/dev/null +>>>2/Malformed JSON/ >>>= !0 # 4. Test that a non-existent file is correctly reported -./test/hs/hpc-mon-collector drbd /dev/no-such-file +./test/hs/hpc-mon-collector drbd --drbd-status=/dev/no-such-file --drbd-pairing=/dev/no-such-file >>>2/Error: reading from file: .* does not exist/ >>>= !0 -# 5. Test that multiple files are rejected -./test/hs/hpc-mon-collector drbd /dev/null /dev/null ->>>2/takes only one argument/ +# 5. Test that arguments are rejected +./test/hs/hpc-mon-collector drbd /dev/null +>>>2/takes exactly zero arguments/ >>>= !0 # 6. Test that a standard test file is parsed correctly -./test/hs/hpc-mon-collector drbd $PYTESTDATA_DIR/proc_drbd83.txt +./test/hs/hpc-mon-collector drbd --drbd-status=$PYTESTDATA_DIR/proc_drbd83.txt --drbd-pairing=$PYTESTDATA_DIR/instance-minor-pairing.txt >>>=0 # 7. Test that the drbd collector fails parsing /dev/zero, but is not # stuck forever printing \NUL chars -./test/hs/hpc-mon-collector drbd /dev/zero +./test/hs/hpc-mon-collector drbd --drbd-status=/dev/zero --drbd-pairing=$PYTESTDATA_DIR/instance-minor-pairing.txt >>>2 Error: "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL" []