'Directly send a JSON object: "raw <method> <path> <data> <notoken>"
<method>: Required. One of "PUT", "GET", "POST", "xPUT", "xGET",
"xPOST". Methods with \'x\' prefixed will not automatically append the
access token.
<path>: Required. E.g. "/events"
<data>: Optional. E.g. "{ "msgtype":"custom.text", "body":"abc123"}"'

def do_raw(self, line):

    args = self._parse(line, ['method', 'path', 'data'])
    if (('method' not in args) or ('path' not in args)):
        print 'Must    specify    path    and    method.'
        return
    args['method'] = args['method'].upper()
    valid_methods = ['PUT', 'GET', 'POST', 'DELETE', 'XPUT', 'XGET', 'XPOST', 'XDELETE']
    if (args['method'] not in valid_methods):
        print ('Unsupported    method:    %s' % args['method'])
        return
    if ('data' not in args):
        args['data'] = None
    else:
        try:
            args['data'] = json.loads(args['data'])
        except Exception as e:
            print ('Data    is    not    valid    JSON.    %s' % e)
            return
    qp = {'access_token': self._tok()}
    if args['method'].startswith('X'):
        qp = {}
        args['method'] = args['method'][1:]
    else:
        try:
            parsed_url = urlparse.urlparse(args['path'])
            qp.update(urlparse.parse_qs(parsed_url.query))
            args['path'] = parsed_url.path
        except:
            pass
    reactor.callFromThread(self._run_and_pprint, args['method'], args['path'], args['data'], query_params=qp)
