blob: 63caa447bbd019ef239251c52bc51e19c027de67 [file] [log] [blame]
Junxiao Shi0fcb41e2014-01-24 10:29:43 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shifc206962015-01-16 11:12:22 -07003 * Copyright (c) 2014-2015, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080010 *
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070011 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Junxiao Shia9388182014-12-13 23:16:09 -070024 */
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070025
26#include "table/cs.hpp"
Junxiao Shia9388182014-12-13 23:16:09 -070027#include <ndn-cxx/util/crypto.hpp>
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080028
Junxiao Shid9ee45c2014-02-27 15:38:11 -070029#include "tests/test-common.hpp"
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080030
mzhang4eab72492015-02-25 11:16:09 -060031#define CHECK_CS_FIND(expected) find([&] (uint32_t found) { BOOST_CHECK_EQUAL(expected, found); });
32
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080033namespace nfd {
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080034namespace cs {
Junxiao Shid9ee45c2014-02-27 15:38:11 -070035namespace tests {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070036
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080037using namespace nfd::tests;
38
Junxiao Shid9ee45c2014-02-27 15:38:11 -070039BOOST_FIXTURE_TEST_SUITE(TableCs, BaseFixture)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070040
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080041class FindFixture : protected BaseFixture
42{
43protected:
Junxiao Shia9388182014-12-13 23:16:09 -070044 Name
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080045 insert(uint32_t id, const Name& name)
46 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040047 shared_ptr<Data> data = makeData(name);
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070048 data->setFreshnessPeriod(time::milliseconds(99999));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080049 data->setContent(reinterpret_cast<const uint8_t*>(&id), sizeof(id));
Junxiao Shia9388182014-12-13 23:16:09 -070050 data->wireEncode();
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070051
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080052 m_cs.insert(*data);
Junxiao Shia9388182014-12-13 23:16:09 -070053
54 return data->getFullName();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080055 }
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070056
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080057 Interest&
58 startInterest(const Name& name)
59 {
60 m_interest = make_shared<Interest>(name);
61 return *m_interest;
62 }
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070063
mzhang4eab72492015-02-25 11:16:09 -060064 void
65 find(const std::function<void(uint32_t)>& check)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080066 {
mzhang4eab72492015-02-25 11:16:09 -060067 m_cs.find(*m_interest,
68 [&] (const Interest& interest, const Data& data) {
69 const Block& content = data.getContent();
70 uint32_t found = *reinterpret_cast<const uint32_t*>(content.value());
71 check(found); },
72 bind([&] { check(0); }));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080073 }
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070074
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080075protected:
76 Cs m_cs;
77 shared_ptr<Interest> m_interest;
78};
79
80BOOST_FIXTURE_TEST_SUITE(Find, FindFixture)
81
82BOOST_AUTO_TEST_CASE(EmptyDataName)
83{
84 insert(1, "ndn:/");
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070085
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080086 startInterest("ndn:/");
mzhang4eab72492015-02-25 11:16:09 -060087 CHECK_CS_FIND(1);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080088}
89
90BOOST_AUTO_TEST_CASE(EmptyInterestName)
91{
92 insert(1, "ndn:/A");
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070093
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080094 startInterest("ndn:/");
mzhang4eab72492015-02-25 11:16:09 -060095 CHECK_CS_FIND(1);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080096}
97
Junxiao Shia9388182014-12-13 23:16:09 -070098BOOST_AUTO_TEST_CASE(ExactName)
99{
100 insert(1, "ndn:/");
101 insert(2, "ndn:/A");
102 insert(3, "ndn:/A/B");
103 insert(4, "ndn:/A/C");
104 insert(5, "ndn:/D");
105
106 startInterest("ndn:/A");
mzhang4eab72492015-02-25 11:16:09 -0600107 CHECK_CS_FIND(2);
Junxiao Shia9388182014-12-13 23:16:09 -0700108}
109
110BOOST_AUTO_TEST_CASE(FullName)
111{
112 Name n1 = insert(1, "ndn:/A");
113 Name n2 = insert(2, "ndn:/A");
114
115 startInterest(n1);
mzhang4eab72492015-02-25 11:16:09 -0600116 CHECK_CS_FIND(1);
Junxiao Shia9388182014-12-13 23:16:09 -0700117
118 startInterest(n2);
mzhang4eab72492015-02-25 11:16:09 -0600119 CHECK_CS_FIND(2);
Junxiao Shia9388182014-12-13 23:16:09 -0700120}
121
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800122BOOST_AUTO_TEST_CASE(Leftmost)
123{
124 insert(1, "ndn:/A");
125 insert(2, "ndn:/B/p/1");
126 insert(3, "ndn:/B/p/2");
127 insert(4, "ndn:/B/q/1");
128 insert(5, "ndn:/B/q/2");
129 insert(6, "ndn:/C");
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700130
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800131 startInterest("ndn:/B");
mzhang4eab72492015-02-25 11:16:09 -0600132 CHECK_CS_FIND(2);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800133}
134
135BOOST_AUTO_TEST_CASE(Rightmost)
136{
137 insert(1, "ndn:/A");
138 insert(2, "ndn:/B/p/1");
139 insert(3, "ndn:/B/p/2");
140 insert(4, "ndn:/B/q/1");
141 insert(5, "ndn:/B/q/2");
142 insert(6, "ndn:/C");
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700143
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800144 startInterest("ndn:/B")
145 .setChildSelector(1);
mzhang4eab72492015-02-25 11:16:09 -0600146 CHECK_CS_FIND(4);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800147}
148
Junxiao Shia9388182014-12-13 23:16:09 -0700149BOOST_AUTO_TEST_CASE(MinSuffixComponents)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800150{
151 insert(1, "ndn:/");
152 insert(2, "ndn:/A");
Junxiao Shia9388182014-12-13 23:16:09 -0700153 insert(3, "ndn:/B/1");
154 insert(4, "ndn:/C/1/2");
155 insert(5, "ndn:/D/1/2/3");
156 insert(6, "ndn:/E/1/2/3/4");
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700157
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800158 startInterest("ndn:/")
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800159 .setMinSuffixComponents(0);
mzhang4eab72492015-02-25 11:16:09 -0600160 CHECK_CS_FIND(1);
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700161
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800162 startInterest("ndn:/")
Junxiao Shia9388182014-12-13 23:16:09 -0700163 .setMinSuffixComponents(1);
mzhang4eab72492015-02-25 11:16:09 -0600164 CHECK_CS_FIND(1);
Junxiao Shia9388182014-12-13 23:16:09 -0700165
166 startInterest("ndn:/")
167 .setMinSuffixComponents(2);
mzhang4eab72492015-02-25 11:16:09 -0600168 CHECK_CS_FIND(2);
Junxiao Shia9388182014-12-13 23:16:09 -0700169
170 startInterest("ndn:/")
171 .setMinSuffixComponents(3);
mzhang4eab72492015-02-25 11:16:09 -0600172 CHECK_CS_FIND(3);
Junxiao Shia9388182014-12-13 23:16:09 -0700173
174 startInterest("ndn:/")
175 .setMinSuffixComponents(4);
mzhang4eab72492015-02-25 11:16:09 -0600176 CHECK_CS_FIND(4);
Junxiao Shia9388182014-12-13 23:16:09 -0700177
178 startInterest("ndn:/")
179 .setMinSuffixComponents(5);
mzhang4eab72492015-02-25 11:16:09 -0600180 CHECK_CS_FIND(5);
Junxiao Shia9388182014-12-13 23:16:09 -0700181
182 startInterest("ndn:/")
183 .setMinSuffixComponents(6);
mzhang4eab72492015-02-25 11:16:09 -0600184 CHECK_CS_FIND(6);
Junxiao Shia9388182014-12-13 23:16:09 -0700185
186 startInterest("ndn:/")
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800187 .setMinSuffixComponents(7);
mzhang4eab72492015-02-25 11:16:09 -0600188 CHECK_CS_FIND(0);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800189}
190
191BOOST_AUTO_TEST_CASE(MaxSuffixComponents)
192{
193 insert(1, "ndn:/");
194 insert(2, "ndn:/A");
Junxiao Shia9388182014-12-13 23:16:09 -0700195 insert(3, "ndn:/B/2");
196 insert(4, "ndn:/C/2/3");
197 insert(5, "ndn:/D/2/3/4");
198 insert(6, "ndn:/E/2/3/4/5");
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700199
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800200 startInterest("ndn:/")
Junxiao Shia9388182014-12-13 23:16:09 -0700201 .setChildSelector(1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800202 .setMaxSuffixComponents(0);
mzhang4eab72492015-02-25 11:16:09 -0600203 CHECK_CS_FIND(0);
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700204
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800205 startInterest("ndn:/")
Junxiao Shia9388182014-12-13 23:16:09 -0700206 .setChildSelector(1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800207 .setMaxSuffixComponents(1);
mzhang4eab72492015-02-25 11:16:09 -0600208 CHECK_CS_FIND(1);
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700209
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800210 startInterest("ndn:/")
Junxiao Shia9388182014-12-13 23:16:09 -0700211 .setChildSelector(1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800212 .setMaxSuffixComponents(2);
mzhang4eab72492015-02-25 11:16:09 -0600213 CHECK_CS_FIND(2);
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700214
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800215 startInterest("ndn:/")
Junxiao Shia9388182014-12-13 23:16:09 -0700216 .setChildSelector(1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800217 .setMaxSuffixComponents(3);
mzhang4eab72492015-02-25 11:16:09 -0600218 CHECK_CS_FIND(3);
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700219
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800220 startInterest("ndn:/")
Junxiao Shia9388182014-12-13 23:16:09 -0700221 .setChildSelector(1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800222 .setMaxSuffixComponents(4);
mzhang4eab72492015-02-25 11:16:09 -0600223 CHECK_CS_FIND(4);
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700224
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800225 startInterest("ndn:/")
Junxiao Shia9388182014-12-13 23:16:09 -0700226 .setChildSelector(1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800227 .setMaxSuffixComponents(5);
mzhang4eab72492015-02-25 11:16:09 -0600228 CHECK_CS_FIND(5);
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700229
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800230 startInterest("ndn:/")
Junxiao Shia9388182014-12-13 23:16:09 -0700231 .setChildSelector(1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800232 .setMaxSuffixComponents(6);
mzhang4eab72492015-02-25 11:16:09 -0600233 CHECK_CS_FIND(6);
Junxiao Shia9388182014-12-13 23:16:09 -0700234
235 startInterest("ndn:/")
236 .setChildSelector(1)
237 .setMaxSuffixComponents(7);
mzhang4eab72492015-02-25 11:16:09 -0600238 CHECK_CS_FIND(6);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800239}
240
241BOOST_AUTO_TEST_CASE(DigestOrder)
242{
243 insert(1, "ndn:/A");
244 insert(2, "ndn:/A");
245 // We don't know which comes first, but there must be some order
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700246
mzhang4eab72492015-02-25 11:16:09 -0600247 int leftmost = 0, rightmost = 0;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800248 startInterest("ndn:/A")
249 .setChildSelector(0);
mzhang4eab72492015-02-25 11:16:09 -0600250 m_cs.find(*m_interest,
251 [&leftmost] (const Interest& interest, const Data& data) {
252 leftmost = *reinterpret_cast<const uint32_t*>(data.getContent().value());},
253 bind([] { BOOST_CHECK(false); }));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800254 startInterest("ndn:/A")
255 .setChildSelector(1);
mzhang4eab72492015-02-25 11:16:09 -0600256 m_cs.find(*m_interest,
257 [&rightmost] (const Interest, const Data& data) {
258 rightmost = *reinterpret_cast<const uint32_t*>(data.getContent().value()); },
259 bind([] { BOOST_CHECK(false); }));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800260 BOOST_CHECK_NE(leftmost, rightmost);
261}
262
263BOOST_AUTO_TEST_CASE(DigestExclude)
264{
Junxiao Shia9388182014-12-13 23:16:09 -0700265 insert(1, "ndn:/A");
266 Name n2 = insert(2, "ndn:/A");
267 insert(3, "ndn:/A/B");
268
269 uint8_t digest00[ndn::crypto::SHA256_DIGEST_SIZE];
270 std::fill_n(digest00, sizeof(digest00), 0x00);
271 uint8_t digestFF[ndn::crypto::SHA256_DIGEST_SIZE];
272 std::fill_n(digestFF, sizeof(digestFF), 0xFF);
273
274 Exclude excludeDigest;
275 excludeDigest.excludeRange(
276 name::Component::fromImplicitSha256Digest(digest00, sizeof(digest00)),
277 name::Component::fromImplicitSha256Digest(digestFF, sizeof(digestFF)));
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700278
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800279 startInterest("ndn:/A")
Junxiao Shia9388182014-12-13 23:16:09 -0700280 .setChildSelector(0)
281 .setExclude(excludeDigest);
mzhang4eab72492015-02-25 11:16:09 -0600282 CHECK_CS_FIND(3);
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -0700283
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800284 startInterest("ndn:/A")
285 .setChildSelector(1)
Junxiao Shia9388182014-12-13 23:16:09 -0700286 .setExclude(excludeDigest);
mzhang4eab72492015-02-25 11:16:09 -0600287 CHECK_CS_FIND(3);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400288
Junxiao Shia9388182014-12-13 23:16:09 -0700289 Exclude excludeGeneric;
290 excludeGeneric.excludeAfter(name::Component(static_cast<uint8_t*>(nullptr), 0));
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400291
Junxiao Shia9388182014-12-13 23:16:09 -0700292 startInterest("ndn:/A")
293 .setChildSelector(0)
294 .setExclude(excludeGeneric);
mzhang4eab72492015-02-25 11:16:09 -0600295 find([] (uint32_t found) { BOOST_CHECK(found == 1 || found == 2); });
Junxiao Shia9388182014-12-13 23:16:09 -0700296
297 startInterest("ndn:/A")
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400298 .setChildSelector(1)
Junxiao Shia9388182014-12-13 23:16:09 -0700299 .setExclude(excludeGeneric);
mzhang4eab72492015-02-25 11:16:09 -0600300 find([] (uint32_t found) { BOOST_CHECK(found == 1 || found == 2); });
Junxiao Shia9388182014-12-13 23:16:09 -0700301
302 Exclude exclude2 = excludeGeneric;
303 exclude2.excludeOne(n2.get(-1));
304
305 startInterest("ndn:/A")
306 .setChildSelector(0)
307 .setExclude(exclude2);
mzhang4eab72492015-02-25 11:16:09 -0600308 CHECK_CS_FIND(1);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400309
Junxiao Shia9388182014-12-13 23:16:09 -0700310 startInterest("ndn:/A")
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400311 .setChildSelector(1)
Junxiao Shia9388182014-12-13 23:16:09 -0700312 .setExclude(exclude2);
mzhang4eab72492015-02-25 11:16:09 -0600313 CHECK_CS_FIND(1);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400314}
315
Junxiao Shia9388182014-12-13 23:16:09 -0700316BOOST_AUTO_TEST_SUITE_END()
317
Junxiao Shi0de23a22015-12-03 20:07:02 +0000318BOOST_AUTO_TEST_CASE(CachePolicyNoCache)
Junxiao Shi35b16b12015-02-16 22:14:57 -0700319{
320 Cs cs(3);
321
322 shared_ptr<Data> dataA = makeData("ndn:/A");
Junxiao Shi35b16b12015-02-16 22:14:57 -0700323 dataA->wireEncode();
Junxiao Shi0de23a22015-12-03 20:07:02 +0000324
325 dataA->setTag(make_shared<lp::CachePolicyTag>(
326 lp::CachePolicy().setPolicy(lp::CachePolicyType::NO_CACHE)));
327
Junxiao Shi35b16b12015-02-16 22:14:57 -0700328 BOOST_CHECK_EQUAL(cs.insert(*dataA), false);
329
mzhang4eab72492015-02-25 11:16:09 -0600330 cs.find(Interest("ndn:/A"),
331 bind([] { BOOST_CHECK(false); }),
332 bind([] { BOOST_CHECK(true); }));
Junxiao Shi35b16b12015-02-16 22:14:57 -0700333}
334
Junxiao Shifc206962015-01-16 11:12:22 -0700335BOOST_AUTO_TEST_CASE(Enumeration)
336{
337 Cs cs;
338
339 Name nameA("/A");
340 Name nameAB("/A/B");
341 Name nameABC("/A/B/C");
342 Name nameD("/D");
343
344 BOOST_CHECK_EQUAL(cs.size(), 0);
345 BOOST_CHECK(cs.begin() == cs.end());
346
347 cs.insert(*makeData(nameABC));
348 BOOST_CHECK_EQUAL(cs.size(), 1);
349 BOOST_CHECK(cs.begin() != cs.end());
350 BOOST_CHECK(cs.begin()->getName() == nameABC);
351 BOOST_CHECK((*cs.begin()).getName() == nameABC);
352
353 auto i = cs.begin();
354 auto j = cs.begin();
355 BOOST_CHECK(++i == cs.end());
356 BOOST_CHECK(j++ == cs.begin());
357 BOOST_CHECK(j == cs.end());
358
359 cs.insert(*makeData(nameA));
360 cs.insert(*makeData(nameAB));
361 cs.insert(*makeData(nameD));
362
363 std::set<Name> expected = {nameA, nameAB, nameABC, nameD};
364 std::set<Name> actual;
365 for (const auto& csEntry : cs) {
366 actual.insert(csEntry.getName());
367 }
368 BOOST_CHECK_EQUAL_COLLECTIONS(actual.begin(), actual.end(), expected.begin(), expected.end());
369}
370
Junxiao Shia9388182014-12-13 23:16:09 -0700371BOOST_AUTO_TEST_SUITE_END()
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -0800372
Junxiao Shid9ee45c2014-02-27 15:38:11 -0700373} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800374} // namespace cs
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800375} // namespace nfd