{"action":"created","comment":{"url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/comments/86465267","pull_request_review_id":7118775,"id":86465267,"diff_hunk":"@@ -0,0 +1,939 @@\n+#ifndef RDFS_ZKNNCLIENT_CC\n+#define RDFS_ZKNNCLIENT_CC\n+\n+#include \"../include/zk_nn_client.h\"\n+#include \"zkwrapper.h\"\n+#include <iostream>\n+#include <sstream>\n+#include <ctime>\n+#include <chrono>\n+#include <sys/time.h>\n+#include \"zk_lock.h\"\n+\n+#include \"hdfs.pb.h\"\n+#include \"ClientNamenodeProtocol.pb.h\"\n+#include <google/protobuf/message.h>\n+#include <ConfigReader.h>\n+#include <easylogging++.h>\n+\n+#include <boost/uuid/uuid.hpp>\n+#include <boost/uuid/uuid_generators.hpp>\n+#include <boost/algorithm/string.hpp>\n+#include \"zk_dn_client.h\"\n+\n+namespace zkclient{\n+\n+\tusing namespace hadoop::hdfs;\n+\n+\tconst std::string ZkNnClient::CLASS_NAME = \": **ZkNnClient** : \";\n+\n+\tZkNnClient::ZkNnClient(std::string zkIpAndAddress) : ZkClientCommon(zkIpAndAddress) {\n+\t\tmkdir_helper( \"/\", false);\n+\t}\n+\n+\tZkNnClient::ZkNnClient(std::shared_ptr <ZKWrapper> zk_in) : ZkClientCommon(zk_in) {\n+\t\tmkdir_helper( \"/\", false);\n+\t}\n+\n+\t/*\n+\t * A simple print function that will be triggered when\n+\t * namenode loses a heartbeat\n+\t */\n+\tvoid notify_delete() {\n+\t\tprintf(\"No heartbeat, no childs to retrieve\\n\");\n+\t}\n+\n+\tvoid ZkNnClient::register_watches() {\n+\n+\t\tint error_code;\n+\t\t// TODO: Do we have to free the returned children?\n+\t\tstd::vector <std::string> children = std::vector <std::string>();\n+\n+\t\t/* Place a watch on the health subtree */\n+\n+\n+\t\tif (!(zk->wget_children(HEALTH, children, zk->watcher_health_factory(ZkClientCommon::HEALTH_BACKSLASH), nullptr, error_code))) {\n+\t\t\t\t// TODO: Handle error\n+\t\t\t\tLOG(ERROR) << CLASS_NAME << \"[In register_watchers], wget failed \" << error_code;\n+\t\t\t}\n+\n+\t\tfor (int i = 0; i < children.size(); i++) {\n+\t\t\tLOG(INFO) << CLASS_NAME << \"[In register_watches] Attaching child to \" << children[i] << \", \";\n+\t\t\tstd::vector <std::string> ephem = std::vector <std::string>();\n+\t\t\tif(!(zk->wget_children(HEALTH_BACKSLASH + children[i], ephem, zk->watcher_health_child, nullptr, error_code))) {\n+\t\t\t\t// TODO: Handle error\n+\t\t\t\tLOG(ERROR) << CLASS_NAME << \"[In register_watchers], wget failed \" << error_code;\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t   if (ephem.size() > 0) {\n+\t\t\t   LOG(INFO) << CLASS_NAME << \"Found ephem \" << ephem[0];\n+\t\t\t   } else {\n+\t\t\t   LOG(INFO) << CLASS_NAME << \"No ephem found for \" << children[i];\n+\t\t\t   }\n+\t\t\t */\n+\t\t}\n+\t}\n+\n+\tbool ZkNnClient::file_exists(const std::string& path) {\n+\t\tbool exists;\n+\t\tint error_code;\n+\t\tif (zk->exists(ZookeeperPath(path), exists, error_code)) {\n+\t\t\treturn exists;\n+\t\t} else {\n+\t\t\t// TODO: Handle error\n+\t\t}\n+\t}\n+\n+\n+\n+\t// --------------------------- PROTOCOL CALLS ---------------------------------------\n+\n+\tvoid ZkNnClient::read_file_znode(FileZNode& znode_data, const std::string& path) {\n+\t\tint error_code;\n+\t\tstd::vector<std::uint8_t> data(sizeof(znode_data));\n+\t\tif (!zk->get(ZookeeperPath(path), data, error_code)) {\n+\t\t\tLOG(INFO) << \"helllo its bad news \" << path;\n+\t\t\t// TODO handle error\n+\t\t}\n+\t\tstd::uint8_t *buffer = &data[0];\n+\t\tmemcpy(&znode_data, buffer, sizeof(znode_data));\n+\t}\n+\n+\tvoid ZkNnClient::file_znode_struct_to_vec(FileZNode* znode_data, std::vector<std::uint8_t>& data) {\n+\t\tmemcpy(&data[0], znode_data, sizeof(*znode_data));\n+\t}\n+\n+\tvoid ZkNnClient::add_block(AddBlockRequestProto& req, AddBlockResponseProto& res) {\n+\n+\t\t// Build a new block for the response\n+\t\tauto block = res.mutable_block();\n+\n+\t\t// TODO: Make sure we are appending / not appending ZKPath at every step....\n+\t\tconst std::string file_path = req.src();\n+\n+\t\tLOG(INFO) << CLASS_NAME << \"Attempting to add block to existing file \" << file_path;\n+\n+\t\tFileZNode znode_data;\n+\t\tif (!file_exists(file_path)) {\n+\t\t\tLOG(ERROR) << CLASS_NAME << \"Requested file \" << file_path << \" does not exist\";\n+\t\t\treturn;\n+\t\t}\n+\t\tread_file_znode(znode_data, file_path); // TODO: What if the file does not exist\n+\t\tif (znode_data.filetype != IS_FILE) { // Assert that the znode we want to modify is a file\n+\t\t\tLOG(ERROR) << CLASS_NAME << \"Requested file \" << file_path << \" is not a file\";\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tuint32_t replication_factor = znode_data.replication;\n+\t\tuint64_t block_size = znode_data.blocksize;\n+\t\tassert(block_size > 0);\n+\n+\t\tu_int64_t block_id;\n+\t\tauto data_nodes = std::vector<std::string>();\n+\n+\t\tadd_block(file_path, block_id, data_nodes, replication_factor);\n+\n+\t\tblock->set_offset(0); // TODO: Set this\n+\t\tblock->set_corrupt(false);\n+\n+\t\tExtendedBlockProto* eb = block->mutable_b();\n+\t\teb->set_poolid(\"0\");\n+\t\teb->set_blockid(block_id);\n+\t\teb->set_generationstamp(1);\n+\t\teb->set_numbytes(block_size);\n+\n+\t\tfor (auto data_node :data_nodes) {\n+\n+\t\t\tint error_code;\n+\n+\t\t\tstd::vector<std::string> split_address;\n+\t\t\tboost::split(split_address, data_node, boost::is_any_of(\":\"));\n+\t\t\tassert(split_address.size() == 2);\n+\n+\t\t\tauto data = std::vector<std::uint8_t>();\n+\t\t\tif (zk->get(HEALTH_BACKSLASH + data_node + STATS, data, error_code)) {\n+\t\t\t\tLOG(ERROR) << CLASS_NAME << \"Getting data node stats failed with \" << error_code;\n+\t\t\t}\n+\n+\t\t\tzkclient::DataNodePayload * payload = (zkclient::DataNodePayload *) (&data[0]);\n+\n+\t\t\tDatanodeInfoProto* dn_info = block->add_locs();\n+\t\t\tDatanodeIDProto* id = dn_info->mutable_id();\n+\t\t\tid->set_ipaddr(split_address[0]);\n+\t\t\tid->set_hostname(\"localhost\"); // TODO: Fill out with the proper value\n+\t\t\tid->set_datanodeuuid(\"1234\");\n+\t\t\tid->set_xferport(payload->xferPort);\n+\t\t\tid->set_infoport(50020);\n+\t\t\tid->set_ipcport(payload->ipcPort);\n+\t\t}\n+\n+\t\t// Construct security token.\n+\t\thadoop::common::TokenProto* token = block->mutable_blocktoken();\n+\t\t// TODO what do these mean\n+\t\ttoken->set_identifier(\"open\");\n+\t\ttoken->set_password(\"sesame\");\n+\t\ttoken->set_kind(\"foo\");\n+\t\ttoken->set_service(\"bar\");\n+\t}\n+\n+\tvoid ZkNnClient::get_info(GetFileInfoRequestProto& req, GetFileInfoResponseProto& res) {\n+\t\tconst std::string& path = req.src();\n+\n+\t\tif (file_exists(path)) {\n+\t\t\tLOG(INFO) << CLASS_NAME << \"File exists\";\n+\t\t\t// read the node into the file node struct\n+\t\t\tFileZNode znode_data;\n+\t\t\tread_file_znode(znode_data, path);\n+\n+\t\t\t// set the file status in the get file info response res\n+\t\t\tHdfsFileStatusProto* status = res.mutable_fs();\n+\n+\t\t\tset_file_info(status, path, znode_data);\n+\t\t\tLOG(INFO) << CLASS_NAME << \"Got info for file \";\n+\t\t\treturn;\n+\t\t}\n+\t\tLOG(INFO) << CLASS_NAME << \"No file to get info for\";\n+\t}\n+\n+\t/**\n+\t * Create a node in zookeeper corresponding to a file\n+\t */\n+\tint ZkNnClient::create_file_znode(const std::string& path, FileZNode* znode_data) {\n+\t\tint error_code;\n+\t\tif (!file_exists(path)) {\n+\t\t\tLOG(INFO)<< \"Creating file znode at \" << path;\n+\t\t\t{\n+\t\t\t\tLOG(INFO) << CLASS_NAME << znode_data->replication;\n+\t\t\t\tLOG(INFO) << CLASS_NAME << znode_data->owner;\n+\t\t\t\tLOG(INFO) << CLASS_NAME << \"size of znode is \" << sizeof(*znode_data);\n+\t\t\t}\n+\t\t\t// serialize struct to byte vector\n+\t\t\tstd::vector<std::uint8_t> data(sizeof(*znode_data));\n+\t\t\tfile_znode_struct_to_vec(znode_data, data);\n+\t\t\t// crate the node in zookeeper\n+\t\t\tif (!zk->create(ZookeeperPath(path), data, error_code)) {\n+\t\t\t\tLOG(ERROR) << CLASS_NAME << \"Create failed\" << error_code;\n+\t\t\t\treturn 0;\n+\t\t\t\t// TODO : handle error\n+\t\t\t}\n+\t\t\treturn 1;\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\n+\tvoid ZkNnClient::delete_node_wrapper(std::string& path, DeleteResponseProto& response) {\n+\t\tint error_code;\n+\t\tif (!zk->delete_node(ZookeeperPath(path), error_code)) {\n+\t\t\tresponse.set_result(false);\n+\t\t\tLOG(ERROR) << CLASS_NAME << \"Error deleting node at \" << path << \" because of error = \" << error_code;\n+\t\t\treturn;\n+\t\t}\n+\t\tLOG(INFO) << CLASS_NAME << \"Successfully deletes znode\";\n+\t}\n+\n+\n+\t/**\n+\t * Go down directories recursively. If a child is a file, then put its deletion on a queue.\n+\t * Files delete themselves, but directories are deleted by their parent (so root can't be deleted)\n+\t */\n+\tvoid ZkNnClient::destroy(DeleteRequestProto& request, DeleteResponseProto& response) {\n+\n+\t\tint error_code;\n+\t\tconst std::string& path = request.src();\n+\t\tbool recursive = request.recursive();\n+\t\tresponse.set_result(true);\n+\t\tif (!file_exists(path)) {\n+\t\t\treturn response.set_result(false);\n+\t\t}\n+\t\tFileZNode znode_data;\n+\t\tread_file_znode(znode_data, path);\n+\n+\t\t// we have a directory\n+\t\tif (recursive) {\n+\t\t\tstd::vector<std::string> children;\n+\t\t\tif (!zk->get_children(ZookeeperPath(path), children, error_code)) {\n+\t\t\t\tLOG(INFO) << CLASS_NAME << \"Could not get children for \" << path << \" because of error = \" << error_code;\n+\t\t\t\tresponse.set_result(false);\n+\t\t\t\t// zlock.unlock();\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t\t// delete the kids\n+\t\t\tfor (auto src : children) {\n+\t\t\t\tDeleteRequestProto request_child;\n+\t\t\t\tDeleteResponseProto response_child;\n+\t\t\t\trequest_child.set_src(path + \"/\" + src);\n+\t\t\t\trequest_child.set_recursive(true);\n+\t\t\t\tdestroy(request_child, response_child);\n+\t\t\t\tif (response_child.result() == false) { // propogate failures updwards\n+\t\t\t\t\tresponse.set_result(false);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\telse if (znode_data.filetype == IS_DIR || znode_data.filetype == IS_DIR1) {\n+\t\t\t//make sure that the directory is empty if we are not recursively deleting it\n+\t\t\tstd::vector<std::string> children;\n+\t\t\tif (!zk->get_children(ZookeeperPath(path), children, error_code) || children.size() > 0) {\n+\t\t\t\tLOG(INFO) << CLASS_NAME << \"Could not get children for \" << path << \" because of error = \" << error_code\n+\t\t\t\t\t<< \" or the directory has children and the delete wasnt recursive\";\n+\t\t\t\tresponse.set_result(false);\n+\t\t\t\t// zlock.unlock();\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t}\n+\t\tstd::string copy = path;\n+\t\t// delete then dude then\n+\t\tdelete_node_wrapper(copy, response);\n+\t\tif (znode_data.filetype == IS_FILE) {\n+\t\t\t// TODO delete his blocks\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * Create a file in zookeeper\n+\t */\n+\tint ZkNnClient::create_file(CreateRequestProto& request, CreateResponseProto& response) {\n+\t\tLOG(INFO) << CLASS_NAME << \"Gonna try and create a file on zookeeper\";\n+\t\tconst std::string& path = request.src();\n+\t\tconst std::string& owner = request.clientname();\n+\t\tbool create_parent = request.createparent();\n+\t\tstd::uint64_t blocksize = request.blocksize();\n+\t\tstd::uint32_t replication = request.replication();\n+\t\tstd::uint32_t createflag = request.createflag();\n+\n+\t\tif (file_exists(path)) {\n+\t\t\t// TODO solve this issue of overwriting files\n+\t\t\tLOG(ERROR) << CLASS_NAME << \"File already exists\";\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\t// If we need to create directories, do so\n+\t\tif (create_parent) {\n+\t\t\tstd::string directory_paths = \"\";\n+\t\t\tauto split_path = split(path, '/');\n+\t\t\tLOG(INFO) << CLASS_NAME << split_path.size();\n+\t\t\tfor (int i = 0; i < split_path.size() - 1; i++) {\n+\t\t\t\tdirectory_paths += split_path[i];\n+\t\t\t}\n+\t\t\t// try and make all the parents\n+\t\t\tif (!mkdir_helper(directory_paths, true))\n+\t\t\t\treturn 0;\n+\t\t}\n+\n+\t\t// Now create the actual file which will hold blocks\n+\t\tFileZNode znode_data;\n+\t\tznode_data.length = 0;\n+\t\tznode_data.under_construction = UNDER_CONSTRUCTION;\n+\t\t// http://stackoverflow.com/questions/19555121/how-to-get-current-timestamp-in-milliseconds-since-1970-just-the-way-java-gets\n+\t\tstruct timeval tp;\n+\t\tgettimeofday(&tp, NULL);\n+\t\tuint64_t mslong = (uint64_t) tp.tv_sec * 1000L + tp.tv_usec / 1000; //get current timestamp in milliseconds\n+\t\tznode_data.access_time = mslong;\n+\t\tznode_data.modification_time = mslong;\n+\t\tstrcpy(znode_data.owner, owner.c_str());\n+\t\tstrcpy(znode_data.group, owner.c_str());\n+\t\tznode_data.replication = replication;\n+\t\tznode_data.blocksize = blocksize;\n+\t\tznode_data.filetype = 2;\n+\n+\t\t// if we failed, then do not set any status\n+\t\tif (!create_file_znode(path, &znode_data))\n+\t\t\treturn 0;\n+\n+\t\tHdfsFileStatusProto* status = response.mutable_fs();\n+\t\tset_file_info(status, path, znode_data);\n+\n+\t\treturn 1;\n+\t}\n+\n+\tvoid ZkNnClient::complete(CompleteRequestProto& req, CompleteResponseProto& res) {\n+\n+\t\t// TODO: Completion makes a few guarantees that we should handle\n+\n+\t\tint error_code;\n+\t\t// change the under construction bit\n+\t\tconst std::string& src = req.src();\n+\t\tFileZNode znode_data;\n+\t\tread_file_znode(znode_data, src);\n+\t\tznode_data.under_construction = FILE_COMPLETE;\n+\t\tstd::vector<std::uint8_t> data(sizeof(znode_data));\n+\t\tfile_znode_struct_to_vec(&znode_data, data);\n+\t\tif (!zk->set(ZookeeperPath(src), data, error_code)) {\n+\t\t\t// TODO : handle erro\n+\t\t}\n+\t\tres.set_result(true);\n+\t}\n+\n+\t/**\n+\t * Rename a file in the zookeeper filesystem\n+\t */\n+\tvoid ZkNnClient::rename(RenameRequestProto& req, RenameResponseProto& res) {\n+\t\tif(!rename_file(req.src(), req.dst())) {\n+\t\t\tres.set_result(false);\n+\t\t}\n+\t\tres.set_result(true);\n+\t}\n+\n+\t// ------- make a directory\n+\n+\t/**\n+\t * Set the default information for a directory znode\n+\t */\n+\tvoid ZkNnClient::set_mkdir_znode(FileZNode* znode_data) {\n+\t\tznode_data->length = 0;\n+\t\tstruct timeval tp;\n+\t\tgettimeofday(&tp, NULL);\n+\t\t// http://stackoverflow.com/questions/19555121/how-to-get-current-timestamp-in-milliseconds-since-1970-just-the-way-java-gets\n+\t\tuint64_t mslong = (uint64_t) tp.tv_sec * 1000L + tp.tv_usec / 1000; //get current timestamp in milliseconds\n+\t\tznode_data->access_time = mslong; // TODO what are these\n+\t\tznode_data->modification_time = mslong;\n+\t\tznode_data->blocksize = 0;\n+\t\tznode_data->replication = 0;\n+\t\tznode_data->filetype = IS_DIR;\n+\t}\n+\n+\t/**\n+\t * Make a directory in zookeeper\n+\t */\n+\tvoid ZkNnClient::mkdir(MkdirsRequestProto& request, MkdirsResponseProto& response) {\n+\t\tconst std::string& path = request.src();\n+\t\tbool create_parent = request.createparent();\n+\t\tif (!mkdir_helper(path, create_parent)) {\n+\t\t\tresponse.set_result(false);\n+\t\t}\n+\t\tresponse.set_result(true);\n+\t}\n+\n+\t/**\n+\t * Helper for creating a direcotyr znode. Iterates over the parents and crates them\n+\t * if necessary.\n+\t */\n+\tbool ZkNnClient::mkdir_helper(const std::string& path, bool create_parent) {\n+\t\tif (create_parent) {\n+\t\t\tauto split_path = split(path, '/');\n+\t\t\tbool not_exist = false;\n+\t\t\tstd::string unroll;\n+\t\t\tstd::string p_path = \"\";\n+\t\t\tfor (int i = 0; i < split_path.size(); i++) {\n+\t\t\t\tp_path += split_path[i] + \"/\";\n+\t\t\t\tif (!file_exists(p_path)) {\n+\t\t\t\t\t// keep track of the path where we start creating directories\n+\t\t\t\t\tif (not_exist == false) {\n+\t\t\t\t\t\tunroll = p_path;\n+\t\t\t\t\t}\n+\t\t\t\t\tnot_exist = true;\n+\t\t\t\t\tFileZNode znode_data;\n+\t\t\t\t\tset_mkdir_znode(&znode_data);\n+\t\t\t\t\tint error;\n+\t\t\t\t\tif ((error = create_file_znode(path, &znode_data))) {\n+\t\t\t\t\t\t// TODO unroll the created directories\n+\t\t\t\t\t\treturn false;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\telse {\n+\t\t\tFileZNode znode_data;\n+\t\t\tset_mkdir_znode(&znode_data);\n+\t\t\treturn create_file_znode(path, &znode_data);\n+\t\t}\n+\t\treturn true;\n+\t}\n+\n+\tvoid ZkNnClient::get_block_locations(GetBlockLocationsRequestProto& req, GetBlockLocationsResponseProto& res) {\n+\n+\t\tint error_code;\n+\n+\t\tconst std::string &src = req.src();\n+\t\tconst std::string zk_path = ZookeeperPath(src);\n+\n+\t\tgoogle::protobuf::uint64 offset = req.offset();\n+\t\tgoogle::protobuf::uint64 length = req.length();\n+\n+\t\tLocatedBlocksProto* blocks = res.mutable_locations();\n+\n+\t\tFileZNode znode_data;\n+\t\tread_file_znode(znode_data, src);\n+\n+\t\tblocks->set_underconstruction(false);\n+\t\tblocks->set_islastblockcomplete(true);\n+\t\tblocks->set_filelength(znode_data.length);\n+\n+\t\tuint64_t block_size = znode_data.blocksize;\n+\n+\t\tLOG(INFO) << CLASS_NAME << \"Block size of \" << zk_path << \" is \" << block_size;\n+\n+\t\tauto sorted_blocks = std::vector<std::string>();\n+\n+\t\t// TODO: Make more efficient\n+\t\tif(!zk->get_children(zk_path, sorted_blocks, error_code)) {\n+\t\t\tLOG(ERROR) << CLASS_NAME << \"Failed getting children of \" << zk_path << \" with error: \" << error_code;\n+\t\t}\n+\t\tuint64_t size = 0;\n+\t\tfor (auto sorted_block : sorted_blocks) {\n+\t\t\tLOG(INFO) << CLASS_NAME << \"Considering block \" << sorted_block;\n+\t\t\tif (size > offset + length) {\n+\t\t\t\t// at this point the start of the block is at a higher offset than the segment we want\n+\t\t\t\tLOG(INFO) << CLASS_NAME << \"Breaking at block \" << sorted_block;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (size + block_size >= offset) {\n+\t\t\t\tauto data = std::vector<uint8_t>();\n+\t\t\t\tif (!zk->get(zk_path + \"/\" + sorted_block, data, error_code)) {\n+\t\t\t\t\tLOG(ERROR) << CLASS_NAME << \"Failed to get \" << zk_path << \"/\" << sorted_block << \" info: \" << error_code;\n+\t\t\t\t\treturn; // TODO: Signal error\n+\t\t\t\t}\n+\t\t\t\tuint64_t block_id = *(uint64_t *)(&data[0]);\n+\t\t\t\tLOG(INFO) << CLASS_NAME << \"Found block \" << block_id << \" for \" << zk_path;\n+\n+\t\t\t\t// TODO: This block of code should be moved to a function, repeated with add_block\n+\t\t\t\tLocatedBlockProto* located_block = blocks->add_blocks();\n+\t\t\t\tlocated_block->set_corrupt(0);\n+\t\t\t\tlocated_block->set_offset(size); // TODO: This offset may be incorrect\n+\n+\t\t\t\thadoop::common::TokenProto* token = located_block->mutable_blocktoken();\n+\t\t\t\t// TODO what do these mean\n+\t\t\t\ttoken->set_identifier(\"open\");\n+\t\t\t\ttoken->set_password(\"sesame\");\n+\t\t\t\ttoken->set_kind(\"foo\");\n+\t\t\t\ttoken->set_service(\"bar\");\n+\n+\t\t\t\tExtendedBlockProto* block_proto = located_block->mutable_b();\n+\n+\t\t\t\tblock_proto->set_poolid(\"0\");\n+\t\t\t\tblock_proto->set_blockid(block_id);\n+\t\t\t\tblock_proto->set_generationstamp(1); // TODO: Do we have to modify this?\n+\t\t\t\tblock_proto->set_numbytes(block_size);\n+\n+\t\t\t\tauto data_nodes = std::vector<std::string>();\n+\n+\t\t\t\tLOG(INFO) << CLASS_NAME << \"Getting datanode locations for block: \" << \"/block_locations/\" + std::to_string(block_id);\n+\n+\t\t\t\tif (!zk->get_children(\"/block_locations/\" + std::to_string(block_id), data_nodes, error_code)) {\n+\t\t\t\t\tLOG(ERROR) << CLASS_NAME << \"Failed getting datanode locations for block: \" << \"/block_locations/\" + std::to_string(block_id) << \" with error: \" << error_code;\n+\t\t\t\t}\n+\n+\t\t\t\t// TODO: fix me this is wrong.\n+\t\t\t\t// data_nodes.push_back(\"127.0.0.1:50020\");\n+\t\t\t\tLOG(INFO) << CLASS_NAME << \"Found block locations \" << data_nodes.size();\n+\t\t\t\tfor (auto data_node :data_nodes) {\n+\n+\t\t\t\t\tLOG(INFO) << CLASS_NAME << \"Reading data node \" << data_node;\n+\t\t\t\t\tint error_code;\n+\n+\t\t\t\t\tstd::vector<std::string> split_address;\n+\t\t\t\t\tboost::split(split_address, data_node, boost::is_any_of(\":\"));\n+\t\t\t\t\tassert(split_address.size() == 2);\n+\n+\t\t\t\t\tauto data = std::vector<std::uint8_t>();\n+\t\t\t\t\tif (zk->get(HEALTH_BACKSLASH + data_node + STATS, data, error_code)) {\n+\t\t\t\t\t\tLOG(ERROR) << CLASS_NAME << \"Getting data node stats failed with \" << error_code;\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tzkclient::DataNodePayload * payload = (zkclient::DataNodePayload *) (&data[0]);\n+\n+\t\t\t\t\tDatanodeInfoProto* dn_info = located_block->add_locs();\n+\t\t\t\t\tDatanodeIDProto* id = dn_info->mutable_id();\n+\t\t\t\t\tid->set_ipaddr(split_address[0]);\n+\t\t\t\t\tid->set_hostname(\"localhost\"); // TODO: Fill out with the proper value\n+\t\t\t\t\tid->set_datanodeuuid(\"1234\");\n+\t\t\t\t\tid->set_xferport(payload->xferPort);\n+\t\t\t\t\tid->set_infoport(50020);\n+\t\t\t\t\tid->set_ipcport(payload->ipcPort);\n+\t\t\t\t}\n+\t\t\t\t// Then store this block's information\n+\t\t\t}\n+\t\t\tsize += block_size;\n+\t\t}\n+\t}\n+\n+\n+\t// ---------------------------------------- HELPERS ----------------------------------------\n+\n+\tstd::string ZkNnClient::ZookeeperPath(const std::string &hadoopPath){\n+\t\tstd::string zkpath = NAMESPACE_PATH;\n+\t\tif (hadoopPath.size() == 0) {\n+\t\t\tLOG(INFO) << \"real real bad news\";\n+\t\t}\n+\t\tif (hadoopPath.at(0) != '/'){\n+\t\t\tzkpath += \"/\";\n+\t\t}\n+\t\tzkpath += hadoopPath;\n+\t\tif (zkpath.at(zkpath.length() - 1) == '/'){\n+\t\t\tzkpath.at(zkpath.length() - 1) = '\\0';\n+\t\t}\n+\t\treturn zkpath;\n+\t}\n+\n+\tvoid ZkNnClient::set_file_info(HdfsFileStatusProto* status, const std::string& path, FileZNode& znode_data) {\n+\t\tHdfsFileStatusProto_FileType filetype;\n+\t\t// get the filetype, since we do not want to serialize an enum\n+\t\tswitch(znode_data.filetype) {\n+\t\t\tcase(0):\n+\t\t\t\tfiletype = HdfsFileStatusProto::IS_DIR;\n+\t\t\t\tbreak;\n+\t\t\tcase(1):\n+\t\t\t\tfiletype = HdfsFileStatusProto::IS_DIR;\n+\t\t\t\tbreak;\n+\t\t\tcase(2):\n+\t\t\t\tfiletype = HdfsFileStatusProto::IS_FILE;\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tbreak;\n+\n+\t\t}\n+\n+\t\tFsPermissionProto* permission = status->mutable_permission();\n+\t\t// Shorcut to set permission to 777.\n+\t\tpermission->set_perm(~0);\n+\t\t// Set it to be a file with length 1, \"foo\" owner and group, 0\n+\t\t// modification/access time, \"0\" path inode.\n+\t\tstatus->set_filetype(filetype);\n+\t\tstatus->set_path(path);\n+\t\tstatus->set_length(znode_data.length);\n+\t\tstatus->set_blocksize(znode_data.blocksize);\n+\t\tstd::string owner(znode_data.owner);\n+\t\tstd::string group(znode_data.group);\n+\t\tstatus->set_owner(owner);\n+\t\tstatus->set_group(group);\n+\n+\t\tstatus->set_modification_time(znode_data.modification_time);\n+\t\tstatus->set_access_time(znode_data.access_time);\n+\t\tLOG(INFO) << CLASS_NAME << \"Successfully set the file info \";\n+\t}\n+\n+\t/**\n+\t * Split the str by the delimiter and return a vector of the split words\n+\t*/\n+\t\tstd::vector<std::string> ZkNnClient::split(const std::string &str, char delim) {","path":"zookeeper/source/zk_nn_client.cc","position":601,"original_position":607,"commit_id":"a72b8026c11ec085a3709055b7303e8a717e8524","original_commit_id":"b10f4b362140a1dfbb00d26ab77c4aa4918522ed","user":{"login":"nichhk","id":6537426,"avatar_url":"https://avatars.githubusercontent.com/u/6537426?v=3","gravatar_id":"","url":"https://api.github.com/users/nichhk","html_url":"https://github.com/nichhk","followers_url":"https://api.github.com/users/nichhk/followers","following_url":"https://api.github.com/users/nichhk/following{/other_user}","gists_url":"https://api.github.com/users/nichhk/gists{/gist_id}","starred_url":"https://api.github.com/users/nichhk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nichhk/subscriptions","organizations_url":"https://api.github.com/users/nichhk/orgs","repos_url":"https://api.github.com/users/nichhk/repos","events_url":"https://api.github.com/users/nichhk/events{/privacy}","received_events_url":"https://api.github.com/users/nichhk/received_events","type":"User","site_admin":false},"body":"We should make a util file that does things like splitting strings, making uuids, etc. ","created_at":"2016-11-03T23:30:58Z","updated_at":"2016-11-03T23:43:06Z","html_url":"https://github.com/Rice-Comp413-2016/RDFS/pull/47#discussion_r86465267","pull_request_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/47","_links":{"self":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/comments/86465267"},"html":{"href":"https://github.com/Rice-Comp413-2016/RDFS/pull/47#discussion_r86465267"},"pull_request":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/47"}}},"pull_request":{"url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/47","id":92165122,"html_url":"https://github.com/Rice-Comp413-2016/RDFS/pull/47","diff_url":"https://github.com/Rice-Comp413-2016/RDFS/pull/47.diff","patch_url":"https://github.com/Rice-Comp413-2016/RDFS/pull/47.patch","issue_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues/47","number":47,"state":"open","locked":false,"title":"Merge demo work into develop","user":{"login":"pelmers","id":2406051,"avatar_url":"https://avatars.githubusercontent.com/u/2406051?v=3","gravatar_id":"","url":"https://api.github.com/users/pelmers","html_url":"https://github.com/pelmers","followers_url":"https://api.github.com/users/pelmers/followers","following_url":"https://api.github.com/users/pelmers/following{/other_user}","gists_url":"https://api.github.com/users/pelmers/gists{/gist_id}","starred_url":"https://api.github.com/users/pelmers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pelmers/subscriptions","organizations_url":"https://api.github.com/users/pelmers/orgs","repos_url":"https://api.github.com/users/pelmers/repos","events_url":"https://api.github.com/users/pelmers/events{/privacy}","received_events_url":"https://api.github.com/users/pelmers/received_events","type":"User","site_admin":false},"body":"\r\nr? @ everyone!","created_at":"2016-11-03T14:33:08Z","updated_at":"2016-11-03T23:43:06Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9ff0fb19a85b6526df7ab772d4b5d46147900537","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/47/commits","review_comments_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/47/comments","review_comment_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues/47/comments","statuses_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/statuses/a72b8026c11ec085a3709055b7303e8a717e8524","head":{"label":"Rice-Comp413-2016:rpc-client-datanode","ref":"rpc-client-datanode","sha":"a72b8026c11ec085a3709055b7303e8a717e8524","user":{"login":"Rice-Comp413-2016","id":21268758,"avatar_url":"https://avatars.githubusercontent.com/u/21268758?v=3","gravatar_id":"","url":"https://api.github.com/users/Rice-Comp413-2016","html_url":"https://github.com/Rice-Comp413-2016","followers_url":"https://api.github.com/users/Rice-Comp413-2016/followers","following_url":"https://api.github.com/users/Rice-Comp413-2016/following{/other_user}","gists_url":"https://api.github.com/users/Rice-Comp413-2016/gists{/gist_id}","starred_url":"https://api.github.com/users/Rice-Comp413-2016/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rice-Comp413-2016/subscriptions","organizations_url":"https://api.github.com/users/Rice-Comp413-2016/orgs","repos_url":"https://api.github.com/users/Rice-Comp413-2016/repos","events_url":"https://api.github.com/users/Rice-Comp413-2016/events{/privacy}","received_events_url":"https://api.github.com/users/Rice-Comp413-2016/received_events","type":"Organization","site_admin":false},"repo":{"id":66678304,"name":"RDFS","full_name":"Rice-Comp413-2016/RDFS","owner":{"login":"Rice-Comp413-2016","id":21268758,"avatar_url":"https://avatars.githubusercontent.com/u/21268758?v=3","gravatar_id":"","url":"https://api.github.com/users/Rice-Comp413-2016","html_url":"https://github.com/Rice-Comp413-2016","followers_url":"https://api.github.com/users/Rice-Comp413-2016/followers","following_url":"https://api.github.com/users/Rice-Comp413-2016/following{/other_user}","gists_url":"https://api.github.com/users/Rice-Comp413-2016/gists{/gist_id}","starred_url":"https://api.github.com/users/Rice-Comp413-2016/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rice-Comp413-2016/subscriptions","organizations_url":"https://api.github.com/users/Rice-Comp413-2016/orgs","repos_url":"https://api.github.com/users/Rice-Comp413-2016/repos","events_url":"https://api.github.com/users/Rice-Comp413-2016/events{/privacy}","received_events_url":"https://api.github.com/users/Rice-Comp413-2016/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Rice-Comp413-2016/RDFS","description":"The Rice Comp413 class (2016-2017) implementation of HDFS. (This will eventually be put under an open source license, which one TBD).","fork":false,"url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS","forks_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/forks","keys_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/teams","hooks_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/hooks","issue_events_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues/events{/number}","events_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/events","assignees_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/assignees{/user}","branches_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/branches{/branch}","tags_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/tags","blobs_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/refs{/sha}","trees_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/statuses/{sha}","languages_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/languages","stargazers_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/stargazers","contributors_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/contributors","subscribers_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/subscribers","subscription_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/subscription","commits_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/commits{/sha}","git_commits_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/commits{/sha}","comments_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/comments{/number}","issue_comment_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues/comments{/number}","contents_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/contents/{+path}","compare_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/merges","archive_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/downloads","issues_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues{/number}","pulls_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls{/number}","milestones_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/milestones{/number}","notifications_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/labels{/name}","releases_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/releases{/id}","deployments_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/deployments","created_at":"2016-08-26T20:46:18Z","updated_at":"2016-10-05T20:44:06Z","pushed_at":"2016-11-03T20:14:31Z","git_url":"git://github.com/Rice-Comp413-2016/RDFS.git","ssh_url":"git@github.com:Rice-Comp413-2016/RDFS.git","clone_url":"https://github.com/Rice-Comp413-2016/RDFS.git","svn_url":"https://github.com/Rice-Comp413-2016/RDFS","homepage":"","size":1102,"stargazers_count":1,"watchers_count":1,"language":"Protocol Buffer","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":13,"forks":1,"open_issues":13,"watchers":1,"default_branch":"master"}},"base":{"label":"Rice-Comp413-2016:develop","ref":"develop","sha":"4976fafd5fd8eb6c62ac1e1539f4e30e08e6d3ce","user":{"login":"Rice-Comp413-2016","id":21268758,"avatar_url":"https://avatars.githubusercontent.com/u/21268758?v=3","gravatar_id":"","url":"https://api.github.com/users/Rice-Comp413-2016","html_url":"https://github.com/Rice-Comp413-2016","followers_url":"https://api.github.com/users/Rice-Comp413-2016/followers","following_url":"https://api.github.com/users/Rice-Comp413-2016/following{/other_user}","gists_url":"https://api.github.com/users/Rice-Comp413-2016/gists{/gist_id}","starred_url":"https://api.github.com/users/Rice-Comp413-2016/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rice-Comp413-2016/subscriptions","organizations_url":"https://api.github.com/users/Rice-Comp413-2016/orgs","repos_url":"https://api.github.com/users/Rice-Comp413-2016/repos","events_url":"https://api.github.com/users/Rice-Comp413-2016/events{/privacy}","received_events_url":"https://api.github.com/users/Rice-Comp413-2016/received_events","type":"Organization","site_admin":false},"repo":{"id":66678304,"name":"RDFS","full_name":"Rice-Comp413-2016/RDFS","owner":{"login":"Rice-Comp413-2016","id":21268758,"avatar_url":"https://avatars.githubusercontent.com/u/21268758?v=3","gravatar_id":"","url":"https://api.github.com/users/Rice-Comp413-2016","html_url":"https://github.com/Rice-Comp413-2016","followers_url":"https://api.github.com/users/Rice-Comp413-2016/followers","following_url":"https://api.github.com/users/Rice-Comp413-2016/following{/other_user}","gists_url":"https://api.github.com/users/Rice-Comp413-2016/gists{/gist_id}","starred_url":"https://api.github.com/users/Rice-Comp413-2016/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rice-Comp413-2016/subscriptions","organizations_url":"https://api.github.com/users/Rice-Comp413-2016/orgs","repos_url":"https://api.github.com/users/Rice-Comp413-2016/repos","events_url":"https://api.github.com/users/Rice-Comp413-2016/events{/privacy}","received_events_url":"https://api.github.com/users/Rice-Comp413-2016/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Rice-Comp413-2016/RDFS","description":"The Rice Comp413 class (2016-2017) implementation of HDFS. (This will eventually be put under an open source license, which one TBD).","fork":false,"url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS","forks_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/forks","keys_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/teams","hooks_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/hooks","issue_events_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues/events{/number}","events_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/events","assignees_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/assignees{/user}","branches_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/branches{/branch}","tags_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/tags","blobs_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/refs{/sha}","trees_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/statuses/{sha}","languages_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/languages","stargazers_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/stargazers","contributors_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/contributors","subscribers_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/subscribers","subscription_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/subscription","commits_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/commits{/sha}","git_commits_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/git/commits{/sha}","comments_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/comments{/number}","issue_comment_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues/comments{/number}","contents_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/contents/{+path}","compare_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/merges","archive_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/downloads","issues_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues{/number}","pulls_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls{/number}","milestones_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/milestones{/number}","notifications_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/labels{/name}","releases_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/releases{/id}","deployments_url":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/deployments","created_at":"2016-08-26T20:46:18Z","updated_at":"2016-10-05T20:44:06Z","pushed_at":"2016-11-03T20:14:31Z","git_url":"git://github.com/Rice-Comp413-2016/RDFS.git","ssh_url":"git@github.com:Rice-Comp413-2016/RDFS.git","clone_url":"https://github.com/Rice-Comp413-2016/RDFS.git","svn_url":"https://github.com/Rice-Comp413-2016/RDFS","homepage":"","size":1102,"stargazers_count":1,"watchers_count":1,"language":"Protocol Buffer","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":13,"forks":1,"open_issues":13,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/47"},"html":{"href":"https://github.com/Rice-Comp413-2016/RDFS/pull/47"},"issue":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues/47"},"comments":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/issues/47/comments"},"review_comments":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/47/comments"},"review_comment":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/pulls/47/commits"},"statuses":{"href":"https://api.github.com/repos/Rice-Comp413-2016/RDFS/statuses/a72b8026c11ec085a3709055b7303e8a717e8524"}}}}
{"actor":{"display_login":"nichhk"}}