Revision d78970ba

b/Makefile.am
914 914
	test/data/bdev-drbd-net-ip6.txt \
915 915
	test/data/cert1.pem \
916 916
	test/data/cert2.pem \
917
	test/data/instance-minor-pairing.txt \
917 918
	test/data/ip-addr-show-dummy0.txt \
918 919
	test/data/ip-addr-show-lo-ipv4.txt \
919 920
	test/data/ip-addr-show-lo-ipv6.txt \
b/man/mon-collector.rst
33 33
DRBD
34 34
~~~~
35 35

  
36
| drbd [*status-file*]
36
| drbd [ [ **-s** | **\--drbd-status** ] = *status-file* ] [ [ **-p** | **\--drbd-pairing**] = *pairing-file* ]
37 37

  
38 38
Collects the information about the version and status of the DRBD kernel
39 39
module, and of the disks it is managing.
40 40

  
41
If *status-file* is specified, the status will be read from that file.
42
Otherwise, the collector will read it from /proc/drbd.
41
If *status-file* and *pairing-file* are specified, the status and the
42
instance-minor paring information will be read from those files.
43
Otherwise, the collector will read them, respectively, from /proc/drbd
44
and from the Confd server.
45

  
46
The options that can be passed to the DRBD collector are as follows:
47

  
48
-s *status-file*, \--drbd-status=*status-file*
49
  Read the DRBD status from the specified file instead of /proc/drbd.
50

  
51
-p *pairing-file*, \--drbd-pairing=*pairing-file*
52
  Read the information about the pairing between instances and DRBD minors
53
  from the specified file instead of asking the Confd servers for them.
b/src/Ganeti/DataCollectors/CLI.hs
34 34
  , oShowHelp
35 35
  , oShowVer
36 36
  , oShowComp
37
  , oDrbdPairing
38
  , oDrbdStatus
37 39
  , genericOptions
38 40
  ) where
39 41

  
42
import System.Console.GetOpt
43

  
44
import Ganeti.BasicTypes
40 45
import Ganeti.Common as Common
41 46

  
42 47
-- * Data types
......
46 51
  { optShowHelp    :: Bool           -- ^ Just show the help
47 52
  , optShowComp    :: Bool           -- ^ Just show the completion info
48 53
  , optShowVer     :: Bool           -- ^ Just show the program version
54
  , optDrbdStatus  :: Maybe FilePath -- ^ Path to the file containing DRBD
55
                                     -- status information
56
  , optDrbdPairing :: Maybe FilePath -- ^ Path to the file containing pairings
57
                                     -- between instances and DRBD minors
49 58
  } deriving Show
50 59

  
51 60
-- | Default values for the command line options.
......
54 63
  { optShowHelp    = False
55 64
  , optShowComp    = False
56 65
  , optShowVer     = False
66
  , optDrbdStatus  = Nothing
67
  , optDrbdPairing = Nothing
57 68
  }
58 69

  
59 70
-- | Abbreviation for the option type.
......
68 79
  requestComp o = o { optShowComp = True }
69 80

  
70 81
-- * Command line options
82
oDrbdPairing :: OptType
83
oDrbdPairing =
84
  ( Option "p" ["drbd-pairing"]
85
      (ReqArg (\ f o -> Ok o { optDrbdPairing = Just f}) "FILE")
86
      "the FILE containing pairings between instances and DRBD minors",
87
    OptComplFile)
88

  
89
oDrbdStatus :: OptType
90
oDrbdStatus =
91
  ( Option "s" ["drbd-status"]
92
      (ReqArg (\ f o -> Ok o { optDrbdStatus = Just f }) "FILE")
93
      "the DRBD status FILE",
94
    OptComplFile)
71 95

  
72 96
-- | Generic options.
73 97
genericOptions :: [GenericOptType Options]
b/src/Ganeti/DataCollectors/Drbd.hs
31 31

  
32 32

  
33 33
import qualified Control.Exception as E
34
import Control.Monad
34 35
import Data.Attoparsec.Text.Lazy as A
36
import Data.Maybe
35 37
import Data.Text.Lazy (pack, unpack)
36
import Text.JSON
38
import Network.BSD (getHostName)
39
import qualified Text.JSON as J
37 40

  
38 41
import qualified Ganeti.BasicTypes as BT
39 42
import qualified Ganeti.Constants as C
40 43
import Ganeti.Block.Drbd.Parser(drbdStatusParser)
44
import Ganeti.Block.Drbd.Types(DrbdInstMinor)
41 45
import Ganeti.Common
46
import Ganeti.Confd.Client
47
import Ganeti.Confd.Types
42 48
import Ganeti.DataCollectors.CLI
43 49
import Ganeti.Utils
44 50

  
......
56 62
defaultCharNum = 80*20
57 63

  
58 64
options :: IO [OptType]
59
options = return []
65
options =
66
  return
67
    [ oDrbdStatus
68
    , oDrbdPairing
69
    ]
60 70

  
61 71
-- | The list of arguments supported by the program.
62 72
arguments :: [ArgCompletion]
63
arguments = [ArgCompletion OptComplFile 0 (Just 1)]
73
arguments = [ArgCompletion OptComplFile 0 (Just 0)]
64 74

  
65 75
-- * Command line options
66 76

  
77
-- | Get information about the pairing of DRBD minors and Ganeti instances
78
-- on the current node. The information is taken from the Confd client
79
-- or, if a filename is specified, from a JSON encoded file (for testing
80
-- purposes).
81
getPairingInfo :: Maybe String -> IO (BT.Result [DrbdInstMinor])
82
getPairingInfo Nothing = do
83
  curNode <- getHostName
84
  client <- getConfdClient
85
  reply <- query client ReqNodeDrbd $ PlainQuery curNode
86
  return $
87
    case fmap (J.readJSONs . confdReplyAnswer) reply of
88
      Just (J.Ok instMinor) -> BT.Ok instMinor
89
      Just (J.Error msg) -> BT.Bad msg
90
      Nothing -> BT.Bad "No answer from the Confd server"
91
getPairingInfo (Just filename) = do
92
  content <- readFile filename
93
  return $
94
    case J.decode content of
95
      J.Ok instMinor -> BT.Ok instMinor
96
      J.Error msg -> BT.Bad msg
97

  
67 98
-- | Main function.
68 99
main :: Options -> [String] -> IO ()
69
main _ args = do
70
  proc_drbd <- case args of
71
                 [ ] -> return defaultFile
72
                 [x] -> return x
73
                 _   -> exitErr $ "This program takes only one argument," ++
74
                                  " got '" ++ unwords args ++ "'"
100
main opts args = do
101
  let proc_drbd = fromMaybe defaultFile $ optDrbdStatus opts
102
      instMinor = optDrbdPairing opts
103
  unless (null args) . exitErr $ "This program takes exactly zero" ++
104
                                  " arguments, got '" ++ unwords args ++ "'"
75 105
  contents <-
76 106
    ((E.try $ readFile proc_drbd) :: IO (Either IOError String)) >>=
77 107
      exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok
108
  pairingResult <- getPairingInfo instMinor
109
  pairing <- exitIfBad "Can't get pairing info" pairingResult
78 110
  output <-
79
    case A.parse (drbdStatusParser []) $ pack contents of
111
    case A.parse (drbdStatusParser pairing) $ pack contents of
80 112
      A.Fail unparsedText contexts errorMessage -> exitErr $
81 113
        show (Prelude.take defaultCharNum $ unpack unparsedText) ++ "\n"
82 114
          ++ show contexts ++ "\n" ++ errorMessage
83
      A.Done _ drbdStatus -> return $ encode drbdStatus
115
      A.Done _ drbdStatus -> return $ J.encode drbdStatus
84 116
  putStrLn output
b/test/data/instance-minor-pairing.txt
1
[["machine1.example.com",0,"instance1.example.com","disk/0","secondary",
2
"machine2.example.com"]]
b/test/hs/shelltests/htools-mon-collector.test
23 23
>>>= 0
24 24

  
25 25
# 3. Test that the drbd collector fails parsing /dev/null
26
./test/hs/hpc-mon-collector drbd /dev/null
27
>>>2
28
Error: ""
29
[]
30
Failed reading: versionInfo
26
./test/hs/hpc-mon-collector drbd --drbd-status=/dev/null --drbd-pairing=/dev/null
27
>>>2/Malformed JSON/
31 28
>>>= !0
32 29

  
33 30
# 4. Test that a non-existent file is correctly reported
34
./test/hs/hpc-mon-collector drbd /dev/no-such-file
31
./test/hs/hpc-mon-collector drbd --drbd-status=/dev/no-such-file --drbd-pairing=/dev/no-such-file
35 32
>>>2/Error: reading from file: .* does not exist/
36 33
>>>= !0
37 34

  
38
# 5. Test that multiple files are rejected
39
./test/hs/hpc-mon-collector drbd /dev/null /dev/null
40
>>>2/takes only one argument/
35
# 5. Test that arguments are rejected
36
./test/hs/hpc-mon-collector drbd /dev/null
37
>>>2/takes exactly zero arguments/
41 38
>>>= !0
42 39

  
43 40
# 6. Test that a standard test file is parsed correctly
44
./test/hs/hpc-mon-collector drbd $PYTESTDATA_DIR/proc_drbd83.txt
41
./test/hs/hpc-mon-collector drbd --drbd-status=$PYTESTDATA_DIR/proc_drbd83.txt --drbd-pairing=$PYTESTDATA_DIR/instance-minor-pairing.txt
45 42
>>>=0
46 43

  
47 44
# 7. Test that the drbd collector fails parsing /dev/zero, but is not
48 45
# stuck forever printing \NUL chars
49
./test/hs/hpc-mon-collector drbd /dev/zero
46
./test/hs/hpc-mon-collector drbd --drbd-status=/dev/zero --drbd-pairing=$PYTESTDATA_DIR/instance-minor-pairing.txt
50 47
>>>2
51 48
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"
52 49
[]

Also available in: Unified diff