blob: 1480103543293a2c859dfa5ef153386cb7cadffa [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Jeff Thompson5cae5e52013-07-10 19:41:20 -07002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Jeff Thompson5cae5e52013-07-10 19:41:20 -070020 */
21
Jeff Thompson56ec9e22013-08-02 11:34:07 -070022#ifndef NDN_DATA_HPP
Jeff Thompsona0d18c92013-08-06 13:55:32 -070023#define NDN_DATA_HPP
Jeff Thompson5cae5e52013-07-10 19:41:20 -070024
Jeff Thompson46bd45f2013-08-08 16:46:41 -070025#include "common.hpp"
Jeff Thompson53412192013-08-06 13:35:50 -070026#include "name.hpp"
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -080027#include "encoding/block.hpp"
Jeff Thompson25b4e612013-10-10 16:03:24 -070028
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080029#include "signature.hpp"
30#include "meta-info.hpp"
31#include "key-locator.hpp"
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080032#include "management/nfd-local-control-header.hpp"
Jeff Thompson5cae5e52013-07-10 19:41:20 -070033
34namespace ndn {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070035
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080036class Data : public enable_shared_from_this<Data>
37{
Jeff Thompson5cae5e52013-07-10 19:41:20 -070038public:
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -070039 class Error : public std::runtime_error
40 {
41 public:
42 explicit
43 Error(const std::string& what)
44 : std::runtime_error(what)
45 {
46 }
47 };
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070048
Jeff Thompson20af0732013-09-12 17:01:45 -070049 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080050 * @brief Create an empty Data object
Alexander Afanasyev770827c2014-05-13 17:42:55 -070051 *
52 * Note that in certain contexts that use Data::shared_from_this(), Data must be
53 * created using `make_shared`:
54 *
55 * shared_ptr<Data> data = make_shared<Data>();
56 *
57 * Otherwise, Data::shared_from_this() will throw an exception.
Jeff Thompson20af0732013-09-12 17:01:45 -070058 */
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080059 Data();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070060
Jeff Thompson20af0732013-09-12 17:01:45 -070061 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080062 * @brief Create a new Data object with the given name
Alexander Afanasyev770827c2014-05-13 17:42:55 -070063 *
64 * @param name A reference to the name
65 *
66 * Note that in certain contexts that use Data::shared_from_this(), Data must be
67 * created using `make_shared`:
68 *
69 * shared_ptr<Data> data = make_shared<Data>(name);
70 *
71 * Otherwise, Data::shared_from_this() will throw an exception.
Jeff Thompson20af0732013-09-12 17:01:45 -070072 */
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080073 Data(const Name& name);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080074
75 /**
76 * @brief Create a new Data object from wire encoding
Alexander Afanasyev770827c2014-05-13 17:42:55 -070077 *
78 * Note that in certain contexts that use Data::shared_from_this(), Data must be
79 * created using `make_shared`:
80 *
81 * shared_ptr<Data> data = make_shared<Data>(wire);
82 *
83 * Otherwise, Data::shared_from_this() will throw an exception.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080084 */
85 explicit
Alexander Afanasyev197e5652014-06-13 16:56:31 -070086 Data(const Block& wire);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070087
Jeff Thompson25bfdca2013-10-16 17:05:41 -070088 /**
Alexander Afanasyev809805d2014-02-17 17:20:33 -080089 * @brief Fast encoding or block size estimation
Alexander Afanasyev197e5652014-06-13 16:56:31 -070090 *
91 * @param block EncodingEstimator or EncodingBuffer instance
92 * @param wantUnsignedPortionOnly Request only unsigned portion to be encoded in block.
93 * If true, only Name, MetaInfo, Content, and SignatureInfo
94 * blocks will be encoded into the block. Note that there
95 * will be no outer TLV header of the Data packet.
Jeff Thompsonb7aefa002013-09-16 18:22:00 -070096 */
Alexander Afanasyev809805d2014-02-17 17:20:33 -080097 template<bool T>
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -070098 size_t
Alexander Afanasyev197e5652014-06-13 16:56:31 -070099 wireEncode(EncodingImpl<T>& block, bool wantUnsignedPortionOnly = false) const;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700100
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800101 /**
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800102 * @brief Encode to a wire format
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800103 */
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700104 const Block&
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800105 wireEncode() const;
106
107 /**
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700108 * @brief Finalize Data packet encoding with the specified SignatureValue
109 *
110 * @param encoder EncodingBuffer instance, containing Name, MetaInfo, Content, and
111 * SignatureInfo (without outer TLV header of the Data packet).
112 * @param signatureValue SignatureValue block to be added to Data packet to finalize
113 * the wire encoding
114 *
115 * This method is intended to be used in concert with Data::wireEncode(EncodingBuffer&, true)
116 * method to optimize Data packet wire format creation:
117 *
118 * Data data;
119 * ...
120 * EncodingBuffer encoder;
121 * data.wireEncode(encoder, true);
122 * ...
123 * Block signatureValue = <sign_over_unsigned_portion>(encoder.buf(), encoder.size());
124 * data.wireEncode(encoder, signatureValue)
125 */
126 const Block&
127 wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const;
128
129 /**
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800130 * @brief Decode from the wire format
131 */
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700132 void
133 wireDecode(const Block& wire);
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800134
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800135 /**
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700136 * @brief Check if Data is already has wire encoding
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800137 */
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700138 bool
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800139 hasWire() const;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700140
141 ////////////////////////////////////////////////////////////////////
142
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700143 /**
144 * @brief Get name of the Data packet
145 */
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700146 const Name&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800147 getName() const;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700148
Jeff Thompson5cae5e52013-07-10 19:41:20 -0700149 /**
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700150 * @brief Set name to a copy of the given Name
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800151 *
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700152 * @return This Data so that you can chain calls to update values
Jeff Thompson0cd8c4a2013-09-13 17:46:40 -0700153 */
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700154 Data&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800155 setName(const Name& name);
156
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800157 //
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700158
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700159 /**
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700160 * @brief Get full name of Data packet, including the implicit digest
161 *
162 * @throws Error if Data packet doesn't have a full name yet (wire encoding has not been
163 * yet created)
164 */
165 const Name&
166 getFullName() const;
167
168 /**
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700169 * @brief Get MetaInfo block from Data packet
170 */
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700171 const MetaInfo&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800172 getMetaInfo() const;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700173
Jeff Thompson0cd8c4a2013-09-13 17:46:40 -0700174 /**
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700175 * @brief Set metaInfo to a copy of the given MetaInfo
176 *
Jeff Thompson6d591972013-10-17 11:16:32 -0700177 * @return This Data so that you can chain calls to update values.
Jeff Thompson0cd8c4a2013-09-13 17:46:40 -0700178 */
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700179 Data&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800180 setMetaInfo(const MetaInfo& metaInfo);
Jeff Thompson46bd45f2013-08-08 16:46:41 -0700181
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800182 //
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700183
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800184 ///////////////////////////////////////////////////////////////
185 ///////////////////////////////////////////////////////////////
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800186 ///////////////////////////////////////////////////////////////
187 // MetaInfo proxy methods
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800188
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700189 uint32_t
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800190 getContentType() const;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700191
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700192 Data&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800193 setContentType(uint32_t type);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800194
195 //
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700196
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700197 const time::milliseconds&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800198 getFreshnessPeriod() const;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700199
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700200 Data&
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700201 setFreshnessPeriod(const time::milliseconds& freshnessPeriod);
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800202
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800203 //
204
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700205 const name::Component&
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800206 getFinalBlockId() const;
207
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700208 Data&
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800209 setFinalBlockId(const name::Component& finalBlockId);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800210
211 //
212 ///////////////////////////////////////////////////////////////
213 ///////////////////////////////////////////////////////////////
214 ///////////////////////////////////////////////////////////////
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700215
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800216 /**
217 * @brief Get content Block
218 *
219 * To access content value, one can use value()/value_size() or
220 * value_begin()/value_end() methods of the Block class
221 */
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700222 const Block&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800223 getContent() const;
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800224
Jeff Thompson0899c0f2013-09-12 12:15:31 -0700225 /**
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700226 * @brief Set the content from the buffer (buffer will be copied)
227 *
228 * @param buffer Pointer to first byte of the buffer
229 * @param bufferSize Size of the buffer
230 *
Jeff Thompson6d591972013-10-17 11:16:32 -0700231 * @return This Data so that you can chain calls to update values.
Jeff Thompson0899c0f2013-09-12 12:15:31 -0700232 */
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700233 Data&
234 setContent(const uint8_t* buffer, size_t bufferSize);
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800235
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700236 /**
237 * @brief Set the content from the block
238 *
239 * Depending on type of the supplied block, there are two cases:
240 *
241 * - if block.type() == Tlv::Content, then block will be used directly as Data packet's
242 * content (no extra copying)
243 *
244 * - if block.type() != Tlv::Content, then this method will create a new Block with type
245 * Tlv::Content and put block as a nested element in the content Block.
246 *
247 * @param block The Block containing the content to assign
248 *
249 * @return This Data so that you can chain calls to update values.
250 */
251 Data&
252 setContent(const Block& block);
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800253
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700254 /**
255 * @brief Set the content from the pointer to immutable buffer
256 *
257 * This method will create a Block with Tlv::Content and set contentValue as a payload
258 * for this block. Note that this method is very different from setContent(const
259 * Block&), since it does not require that payload should be a valid TLV element.
260 *
261 * @param contentValue The pointer to immutable buffer containing the content to assign
262 *
263 * @return This Data so that you can chain calls to update values.
264 */
265 Data&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700266 setContent(const ConstBufferPtr& contentValue);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800267
268 //
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700269
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700270 const Signature&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800271 getSignature() const;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700272
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800273 /**
274 * @brief Set the signature to a copy of the given signature.
275 * @param signature The signature object which is cloned.
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800276 */
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700277 Data&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800278 setSignature(const Signature& signature);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700279
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700280 Data&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700281 setSignatureValue(const Block& value);
Yingdi Yua4e57672014-02-06 11:16:17 -0800282
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800283 ///////////////////////////////////////////////////////////////
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800284
285 nfd::LocalControlHeader&
286 getLocalControlHeader();
287
288 const nfd::LocalControlHeader&
289 getLocalControlHeader() const;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700290
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700291 uint64_t
Yingdi Yua4e57672014-02-06 11:16:17 -0800292 getIncomingFaceId() const;
293
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700294 Data&
Yingdi Yua4e57672014-02-06 11:16:17 -0800295 setIncomingFaceId(uint64_t incomingFaceId);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700296
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700297public: // EqualityComparable concept
298 bool
299 operator==(const Data& other) const;
300
301 bool
302 operator!=(const Data& other) const;
303
Jeff Thompson5cae5e52013-07-10 19:41:20 -0700304private:
Jeff Thompsonb7aefa002013-09-16 18:22:00 -0700305 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800306 * @brief Clear the wire encoding.
Jeff Thompsonb7aefa002013-09-16 18:22:00 -0700307 */
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700308 void
Jeff Thompson0050abe2013-09-17 12:50:25 -0700309 onChanged();
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800310
311private:
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800312 Name m_name;
313 MetaInfo m_metaInfo;
314 mutable Block m_content;
315 Signature m_signature;
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800316
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800317 mutable Block m_wire;
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700318 mutable Name m_fullName;
Yingdi Yua4e57672014-02-06 11:16:17 -0800319
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800320 nfd::LocalControlHeader m_localControlHeader;
321 friend class nfd::LocalControlHeader;
Jeff Thompson5cae5e52013-07-10 19:41:20 -0700322};
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800323
Alexander Afanasyeva0c5f832014-06-19 13:27:56 -0700324std::ostream&
325operator<<(std::ostream& os, const Data& data);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800326
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800327inline bool
328Data::hasWire() const
329{
330 return m_wire.hasWire();
331}
332
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700333inline const Name&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800334Data::getName() const
335{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800336 return m_name;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800337}
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700338
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700339inline const MetaInfo&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800340Data::getMetaInfo() const
341{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800342 return m_metaInfo;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800343}
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700344
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700345inline uint32_t
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800346Data::getContentType() const
347{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800348 return m_metaInfo.getType();
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800349}
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700350
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700351inline const time::milliseconds&
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800352Data::getFreshnessPeriod() const
353{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800354 return m_metaInfo.getFreshnessPeriod();
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800355}
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700356
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800357inline const name::Component&
358Data::getFinalBlockId() const
359{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800360 return m_metaInfo.getFinalBlockId();
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800361}
362
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800363inline const Signature&
364Data::getSignature() const
365{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800366 return m_signature;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800367}
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700368
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800369inline nfd::LocalControlHeader&
370Data::getLocalControlHeader()
371{
372 return m_localControlHeader;
373}
374
375inline const nfd::LocalControlHeader&
376Data::getLocalControlHeader() const
377{
378 return m_localControlHeader;
379}
380
Yingdi Yua4e57672014-02-06 11:16:17 -0800381inline uint64_t
382Data::getIncomingFaceId() const
383{
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800384 return getLocalControlHeader().getIncomingFaceId();
Yingdi Yua4e57672014-02-06 11:16:17 -0800385}
386
Alexander Afanasyev4ff3c912014-01-03 15:25:02 -0800387
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800388} // namespace ndn
389
Jeff Thompson5cae5e52013-07-10 19:41:20 -0700390#endif